/*
 * IMP Encoder implement.
 *
 * Copyright (C) 2014 Ingenic Semiconductor Co.,Ltd
 * Author: Zoro <yakun.li@ingenic.com>
 */

#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <math.h>
#include <sys/mman.h>
#include <sys/eventfd.h>

#include <constraints.h>
#include <imp/imp_log.h>
#include <imp/imp_system.h>
#include <imp/imp_utils.h>
#include <imp/imp_encoder.h>
#include <system/vbm.h>

#include <system/system.h>
#include <system/module.h>
#include <system/group.h>
#include <system/device.h>
#include <isp/demosaic.h>
#include <system/imp_alloc.h>
#include <system/imp_v4l2.h>
#include <jzm_enc_api_t21.h>
#include <icommon.h>
#include <i264e.h>
#include <ijpege.h>
#include "ijpege_common.h"
#include "hwicodec_common.h"
#ifdef CONFIG_SOC_T30
#include <i265e.h>
#endif
#include "imp_video_common.h"

#include <dsystem/funcs.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
enum funcs_encoder {
	DBG_ENC_INFO,
	DBG_ENC_RC_S,
    DBG_SUPERFRM_INFO,
    DBG_SUPERFRM_INFO_S,
	DBG_ENC_RCFILE_S,
};

/* provide nal buffer to i264e, do not copy nal from i264e */

#define TAG "Encoder"
//#define SHOW_ENCODE_STREAM_TIME
#define NR_MAX_PACK_IN_FRAME 10
//#define SHOW_CHANNEL_BITRATE
#ifdef SHOW_CHANNEL_BITRATE
#define BITRATE_FRAMES_INTERVAL 50
static int bitrate[NR_MAX_ENC_CHN] = { 0 };
static int frmcnt[NR_MAX_ENC_CHN] = { 0 };
static int64_t start_time[NR_MAX_ENC_CHN] = { 0 };
#endif
#define DEMASK_HYSTERETIC_VALUE 2
#define SHARPNESS_STEP_DOWN 20
#define SHARPNESS_STEP_UP 20

extern int g_frame_get_sta_flag;

typedef enum {
	PAD_SYNC_NONE			= 0,
	PAD_SYNC_LEFT_FRAME		= 10,
	PAD_SYNC_LEFT_PAD,
	PAD_SYNC_SUCCESS,
} PadSyncStatus;

typedef struct {
	IMPEncoderDataType	dataType;
	int64_t		timestamp;
	uint32_t	length;
} NALBuffer;

typedef struct {
	uint32_t			seq;
	void 				*stream_buffer;

	uint32_t			pack_count;
	IMPEncoderPack		pack[NR_MAX_PACK_IN_FRAME];
	IMPRefType		    refType;
} FrameStream;

typedef struct {
	int				used_count;
	IMPFrameInfo	*used_frame;
} EncFrmUsedStat;

typedef struct {
	i264e_param_t		i264eParam;
	i264e_t				*i264eHandler;
	i264e_pic_t			xPicIn;
	i264e_pic_t			xPicOut;
	int64_t			pts;
	int					qp;
	pthread_t			StrmTid;
	EncFrmUsedStat		usedStat;
	int					demask_cnt;
	IMPSkipType		created_align_skip_type;
	imp_video_container_t *userDataConstraints;
} I264eData;

typedef struct {
	ijpege_param_t		ijpegeParam;
	ijpege_t				*ijpegeHandler;
	ijpege_pic_t			cPicIn;
	int64_t				pts;
} JpegeData;

typedef struct {
#ifdef CONFIG_SOC_T30
	i265e_param_t		i265eParam;
	i265e_t				*i265eHandler;
	i265e_pic_t			xPicIn;
	i265e_pic_t			xPicOut;
#endif
	int64_t			    pts;
	int					qp;
	pthread_t			StrmTid;
	EncFrmUsedStat		usedStat;
	IMPSkipType		    created_align_skip_type;
	imp_video_container_t *userDataConstraints;
} I265eData;

typedef struct {
	int			nrKeepPadFrame;
	int			timeSyncEnalbe;
	uint64_t	padTime;
	uint64_t	syncTime;
	int64_t		padTimeoutMsec;
} PadFrameAttr;

typedef struct {
	IMPFrameInfo		*padFrame;
	void				*data;
	int (*releaseCallback)(IMPFrameInfo *frame, void *data);
} PadStreamHandler;

typedef struct {
	int						padEnable;
	int						padState;
	sem_t					padFreeHandlerSem;
	sem_t					padBusyHandlerSem;
	sem_t					padDoneHandlerSem;
	imp_video_container_t	*padConstraints;
	IMPAlloc				padTlb;
	PadFrameAttr			padAttr;
	struct timespec			padTimeSpec;
} PadData;

typedef struct EncGroup EncGroup;

struct ncu_data {
	bool is_valid;
	bool is_not_first_frame;
	uint32_t enabled;
	uint32_t data_vaddr;
	uint32_t data_paddr;
	uint32_t data_size;
	uint32_t backup_frame_vaddr;
	uint32_t backup_frame_paddr;
	uint32_t out_frame_vaddr;
	uint32_t out_frame_paddr;
	uint32_t frame_size;
	uint32_t bank_index;
	uint8_t *pri_buf;
};

typedef struct {
	int index;
	EncGroup *enc_group;

	IMPEncoderCHNAttr attr;
	IMPEncoderCHNStat stat;
	uint64_t chnFpsMask;
	uint32_t fpsMaskSize;
	IMPEncoderFrmRate inFrmRate;
	IMPEncoderFrmRate setFrmRate;
	uint32_t setMaxGop;
	int64_t lastFrmTimeStamp;

	int64_t     encodingFrameCnt;
	int64_t     endencodeFrameCnt;
	int64_t     endrelaseFrameCnt;

	int recv_pic;
	int idr_request;

	sem_t wr_sem;
	sem_t rd_sem;
	sem_t poll_sem;
	pthread_mutex_t mutex;
    pthread_mutex_t efd_mutex;
    pthread_cond_t efd_cond;
    int efd;    //a file descriptor refered to the eventfd object
    int64_t event_cnt;

	int nr_stream_buffer;
	int b_fisheye;
	void *stream_buffer_base;	/* NALs buffered here */
	int stream_buffer_size;
	FrameStream *frame_streams;	/* Cyclic Buffer */

	App_Fifo              rd_frameStreamFifo;
	App_Fifo              wr_frameStreamFifo;

	/* resize attribute */
	IMPFrameInfo *resize_frame;
	int resize_AtoA;
	uint16_t *resize_tmp_buf;
	uint8_t  *resize_buf;
	void (*c_resize)(uint8_t* src, uint8_t* dst, int src_w, int src_h, int dst_w, int dst_h, bool is_clip, int clip_offset, int clip_w, int clip_h, c_csp_t format, uint16_t *resize_buf);

	I264eData i264e;
	JpegeData jpege;
	I265eData i265e;
	PadData padData;

	/* Used by demusk */
	int prev_frame_sharpness;
	int prev_frame_qp;

	struct ncu_data ncu_data;

	/* internal Stats */
	struct {
		int drop_frames;
		int	need_encode_frames;
		int64_t start_encode_timestamp;

#ifdef SHOW_ENCODE_STREAM_TIME
        int64_t start_time_raw;
        int64_t end_time_raw;
        int64_t start_time_thread;
        int64_t end_time_thread;
#endif
	} inStat;

	int b_enable_bufshare;
	int ivdc_reset_flag;
	int ivdc_fd;
	int direct_mode;
	int ivdc_mem_line;
	uint8_t frame_type;
} EncChannel;

struct EncGroup {
	int index;
	int nr_enc_chn;
	EncChannel *channel[NR_MAX_ENC_CHN_IN_GROUP];
};

typedef struct {
	Device *device;
	EncGroup encGroup[NR_MAX_ENC_GROUPS];
} Encoder;

static EncChannel g_EncChannel[NR_MAX_ENC_CHN];
static Encoder *gEncoder = NULL;
static pthread_mutex_t g_mutex;
static int g_direct_mode = 0;
//static unsigned char demask_sharpness[] = {128,128,64,64,64,64,32,32,32,32,16,16,16,16,16,16,16,16,8,8,8,8};	//qp:[30,51]

/* NCU params*/
#define NCU_NEED_HOW_MUCH_MEM(FRAME_SIZE)			((FRAME_SIZE) * 5 / 2)
#define MAIN_STREAM_THRESTHOLD						NCU_NEED_HOW_MUCH_MEM(800 * 800)
#define NCU_PRIV_BUF_SIZE							(16 * 1024)
#if 0
static int ncu_preprocess(IMPFrameInfo *frame, struct ncu_data *ncu_data);
#endif
static int channel_ncu_data_init(EncChannel *enc_chn);
static int channel_ncu_data_exit(EncChannel *enc_chn);
static int init_ispmem_info(void);
static bool g_ncu_enabled = false;

void filter2D_SIMD(uint8_t* _dst, uint8_t* psn_addr, uint8_t* _srcOld, uint8_t* _srcNew, int width, int height, int _block_h_size, int _block_w_size, int _skip_h_size, int _skip_w_size, int _blur_radius_size, int _blur_diff_thres, int _pixel_blur_diff_thres, int _diff_num_thres, int ori_width, int ori_height, int psn_max_num, int _mv_block_limit, int _block_h_size_ds, int _block_w_size_ds, int _skip_h_size_ds, int _skip_w_size_ds, int _blur_radius_size_ds, int _blur_diff_thres_change_ds, int _mv_block_limit_ds);

void filter2D(uint8_t* _dst, uint8_t* psn_addr, uint8_t* _srcOld, uint8_t* _srcNew, int width, int height, int block_h_size, int block_w_size, int skip_h_size, int skip_w_size, int blur_radius_size, int blur_diff_thres, int pixel_blur_diff_thres, int diff_num_thres, int ori_width, int ori_height, int psn_max_num, int mv_block_limit, int block_h_size_ds, int block_w_size_ds, int skip_h_size_ds, int skip_w_size_ds, int blur_radius_size_ds, int blur_diff_thres_change_ds, int mv_block_limit_ds);

static Encoder *get_encoder(void)
{
	return gEncoder;
}

static int encoder_init(Encoder *encoder)
{
	/* Encoder initial work here. */

	return 0;
}

static void encoder_exit(Encoder *encoder)
{
	/* Exit work here. */
}

static int encoder_bs_buf_size = 0;
#ifdef CONFIG_SINGLE_BS
#define VPU_BS_BUF_SIZE  (MAX_ENCODER_BS_BUFFER_HEIGHT * MAX_ENCODER_BS_BUFFER_WIDTH + 256)
IMPAlloc alloc_vpu_bs;
sem_t bsbufsem;
#endif
static Encoder *alloc_encoder(void)
{
	Encoder *encoder = NULL;
	int bs_buf_size = 0;
	IMPCPUID cpu_id = get_cpu_id();
#ifdef CONFIG_SINGLE_BS
	if ((cpu_id >= SOC_T10_START) && (cpu_id <= SOC_T10_END)) {
		bs_buf_size = 1280 * 960 / 2;
	} else if ((cpu_id == SOC_T20_NORMAL) || (cpu_id == SOC_T20_LITE)) {
		bs_buf_size = 1920 * 1080 / 2;
	} else if (cpu_id == SOC_T20_X) {
		bs_buf_size = 2560 * 1440 / 2;
	} else if ((cpu_id >= SOC_T23_START) && (cpu_id <= SOC_T23_END)) {
		bs_buf_size = 1920 * 1080;
	} else if ((cpu_id == SOC_T30_LITE) || (cpu_id == SOC_T30_N)) {
		bs_buf_size = 1920 * 1080 / 2;
	} else if ((cpu_id >= SOC_T30_X) && (cpu_id <= SOC_T30_END)) {
		bs_buf_size = 2560 * 1920 / 2;
	} else {
		bs_buf_size = 1920 * 1080;
	}
	if (0 != encoder_bs_buf_size) {
		bs_buf_size = encoder_bs_buf_size;
	}
	IMP_LOG_INFO(TAG, "IMP Alloc BS Buf size:%d\n", bs_buf_size);
	memset(&alloc_vpu_bs, 0, sizeof(alloc_vpu_bs));
	if (IMP_Alloc(&alloc_vpu_bs, bs_buf_size, "vpuBs") < 0) {
		IMP_LOG_ERR(TAG, "IMP_Alloc(%d) failed\n", bs_buf_size);
		return NULL;
	}
	/*printf("%s(%d):alloc_vpu_bs.info.vaddr=%x, alloc_vpu_bs.info.vaddr=%x, alloc_vpu_bs.info.length=%d\n",
		__func__, __LINE__, alloc_vpu_bs.info.vaddr, alloc_vpu_bs.info.paddr, alloc_vpu_bs.info.length);*/

	sem_init(&bsbufsem, 0, 0);
	sem_post(&bsbufsem);
#endif

	Device *dev = alloc_device("Encoder", sizeof(Encoder));

	if (dev == NULL) {
		IMP_LOG_ERR(TAG, "alloc_device() error\n");
#ifdef CONFIG_SINGLE_BS
		IMP_Free(&alloc_vpu_bs, (void *)alloc_vpu_bs.info.vaddr);
		sem_destroy(&bsbufsem);
#endif
		return NULL;
	}
	dev->nr_groups = NR_MAX_ENC_GROUPS;
	dev->dev_id = DEV_ID_ENC;

	encoder = device_pri(dev);
	encoder->device = dev;

	return encoder;
}

static void free_encoder(Encoder *encoder)
{
	if (encoder && encoder->device) {
		Device *dev = encoder->device;
		free_device(dev);
	}

#ifdef CONFIG_SINGLE_BS
	IMP_Free(&alloc_vpu_bs, (void *)alloc_vpu_bs.info.vaddr);
	memset(&alloc_vpu_bs, 0, sizeof(alloc_vpu_bs));
	sem_destroy(&bsbufsem);
#endif
}

static FrameStream *encstrm_to_frmstrm(EncChannel *enc_chn, IMPEncoderStream *stream)
{
	FrameStream *frmstrm = NULL;
	int i;

	for (i = 0; i < enc_chn->nr_stream_buffer; i++) {
		frmstrm = &enc_chn->frame_streams[i];
		if (frmstrm->pack == stream->pack)
			return frmstrm;
	}

	return NULL;
}

/* Pick a empty framestream */
static FrameStream *get_empty_framestream_noblock(EncChannel *enc_chn)
{
	int ret;

	ret = sem_trywait(&enc_chn->wr_sem);
	if (ret < 0) {
		IMP_LOG_VERBOSE(TAG, "enc_chn(%d) wait wr_sem timeout\n", enc_chn->index);
		return NULL;
	}

	FrameStream *frmstrm = Fifo_Dequeue(&enc_chn->wr_frameStreamFifo, AL_WAIT_FOREVER);
	if (!frmstrm) {
		IMP_LOG_ERR(TAG, "Dequeue wr_frameStreamFifo failed\n");
		return NULL;
	}

	return frmstrm;
}

/* After fill the empty framestream, mark is as full */
static int mark_filled_framestream(EncChannel *enc_chn, FrameStream *frmstrm)
{
    uint64_t efd_val = 1;

    pthread_mutex_lock(&enc_chn->efd_mutex);
    write(enc_chn->efd, &efd_val, sizeof(uint64_t));
    enc_chn->event_cnt++;
	sem_post(&enc_chn->rd_sem);
	sem_post(&enc_chn->poll_sem);
    pthread_mutex_unlock(&enc_chn->efd_mutex);
    pthread_cond_signal(&enc_chn->efd_cond);

#ifdef SHOW_ENCODE_STREAM_TIME
    int b_dbg_encstream = !access("/tmp/encstream", F_OK);
    if (b_dbg_encstream) {
        IMP_LOG_DBG(TAG, "%s:chnNum=%d:RAW time=%lld\n", __func__, enc_chn->index, system_gettime(RAW));
    }
#endif

	return 0;
}

/* Get a full framestream for user GetStream */
static FrameStream *get_filled_framestream(EncChannel *enc_chn, int block_flag)
{
	int ret;
	int count = 0;

	if (block_flag == 0) {
		while (1) {
			ret = sem_trywait(&enc_chn->rd_sem);
			if (ret < 0) {
				count ++;
				IMP_LOG_DBG(TAG, "---------get frame faied try again time:%d------\n", count);
				if (count > 3) {
					return NULL;
				}
				usleep(10000);
				continue;
			}else {
				break;
			}
		}
	} else {
		ret = sem_wait(&enc_chn->rd_sem);
	}

	FrameStream *frmstrm = Fifo_Dequeue(&enc_chn->rd_frameStreamFifo, AL_WAIT_FOREVER);
	if (!frmstrm) {
		IMP_LOG_ERR(TAG, "Dequeue rd_frameStreamFifo failed\n");
		return NULL;
	}

	int left_stream;
	sem_getvalue(&enc_chn->rd_sem, &left_stream);
	enc_chn->stat.leftStreamFrames = left_stream;

	return frmstrm;
}

/* After using, release the framestream */
static int release_used_framestream(EncChannel *enc_chn, FrameStream *frmstrm)
{
	Fifo_Queue(&enc_chn->wr_frameStreamFifo, frmstrm, AL_WAIT_FOREVER);
	sem_post(&enc_chn->wr_sem);

	return 0;
}

static int polling_filled_framestream(EncChannel *enc_chn, uint32_t timeout_msec)
{
	int ret;

	if (timeout_msec) {
		struct timespec timespec = {timeout_msec / 1000, (timeout_msec % 1000) * 1000000};
		ret = video_sem_timedwait(&enc_chn->poll_sem, &timespec);
	} else {
		ret = sem_wait(&enc_chn->poll_sem);
	}

	return ret;
}

#define SAVE_BUF
#ifdef SAVE_BUF
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

static int save_open = 0;
static char *save_name = "/mnt/mountdir/dump.bs";
static char *save_sec_name = "/mnt/mountdir/dump1.bs";
static int save_times = 0;
static int save_to_file(uint8_t *buf, int size)
{
	int fd = 0;
	if (save_open == 0) {
		if ((fd = open(save_name, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0) {
			printf("create %s failed\n", save_name);
			return -1;
		}
		save_open = 1;
	} else {
		if ((fd = open(save_name, O_WRONLY | O_APPEND)) < 0) {
			printf("open %s failed\n", save_name);
			return -1;
		}
	}

	if (size != write(fd, buf, size)) {
		printf("write %s %d byte failed\n", save_name, size);
		close(fd);
		return -1;
	}
	close(fd);
	return 0;
}

static int save_to_file_name(char *name, uint8_t *buf, int size)
{
	int fd = 0;
	if ((fd = open(name, O_RDWR | O_CREAT | O_TRUNC, 0777)) < 0) {
		printf("create %s failed\n", name);
		return -1;
	}
	if (size != write(fd, buf, size)) {
		printf("write %s %d byte failed\n", name, size);
		close(fd);
		return -1;
	}
	close(fd);
	return 0;
}
#endif

static int encoder_set_fps_mask(EncChannel *enc_chn, IMPEncoderFrmRate inFrmRate, IMPEncoderFrmRate outFrmRate)
{
	if(inFrmRate.frmRateNum * outFrmRate.frmRateDen == outFrmRate.frmRateNum * inFrmRate.frmRateDen){
		enc_chn->chnFpsMask = 1;
		enc_chn->fpsMaskSize = 1;
		return 0;
	}
	if (inFrmRate.frmRateNum * outFrmRate.frmRateDen > 64) {
		IMP_LOG_ERR(TAG, "inFrmRate.frmRateNum=%u, outFrmRate.frmRateDen=%u\n", inFrmRate.frmRateNum, outFrmRate.frmRateDen);
		return -1;
	}
	int step = inFrmRate.frmRateNum * outFrmRate.frmRateDen * 1000 / (outFrmRate.frmRateNum * inFrmRate.frmRateDen);
	uint64_t bitmap = 0;
	int i = 0, p = 0, n = 0;
	enc_chn->fpsMaskSize = inFrmRate.frmRateNum * outFrmRate.frmRateDen;

	for (i = 0; i < enc_chn->fpsMaskSize; i++) {
		bitmap = bitmap << 1;
		if (i == n) {
			bitmap++;
			p++;
			n = (step * p + 500) / 1000;
		}
	}

	enc_chn->chnFpsMask = bitmap;
	//IMP_LOG_DBG(TAG, "bitmap=%llx, inFrmRate.frmRateNum=%u, inFrmRate.frmRateDen=%u, outFrmRate.frmRateNum=%u, outFrmRate.frmRateDen=%u\n", bitmap, inFrmRate.frmRateNum, inFrmRate.frmRateDen, outFrmRate.frmRateNum, outFrmRate.frmRateDen);

	return 0;
}

int check_inframerate_valid(EncChannel *enc_chn, IMPEncoderFrmRate *checkedFrmRate, IMPFrameInfo *frame)
{
	IMPFrameInfoPriv *framePriv = frameInfo_pri(frame);
	float checkedfps = 0.0, ispfps = 0.0, ratio = 0.0;
	int64_t diffTimeStamp = 0;

	/* filter the first frame */
	if (enc_chn->lastFrmTimeStamp <= 0) {
		enc_chn->lastFrmTimeStamp = frame->timeStamp;
		return 0;
	}

	/* filter same frame */
	diffTimeStamp = frame->timeStamp - enc_chn->lastFrmTimeStamp;
	if (!diffTimeStamp) {
		return 0;
	}

	/* filter the fps modified */
	if (!enc_chn->inFrmRate.frmRateNum || !enc_chn->inFrmRate.frmRateDen
			|| (enc_chn->inFrmRate.frmRateNum * framePriv->i_fps_den != framePriv->i_fps_num * enc_chn->inFrmRate.frmRateDen)) {
		enc_chn->lastFrmTimeStamp = frame->timeStamp;
		return 0;
	}

	ispfps = (float)framePriv->i_fps_num / framePriv->i_fps_den;
	ratio = (float)diffTimeStamp / (((float)1000 / (framePriv->i_fps_num / framePriv->i_fps_den)) * 1000);
	checkedfps = (float)1000000 * ratio / diffTimeStamp;
	checkedFrmRate->frmRateNum = (int)(checkedfps + 0.5);
	checkedFrmRate->frmRateDen = 1;


	if (abs(checkedfps - ispfps) <= 1) {
		enc_chn->lastFrmTimeStamp = frame->timeStamp;
		return 1;
	} else {
		IMP_LOG_ERR(TAG, "enc_chn->lastFrmTimeStamp=%lld, frame->timeStamp=%lld\n", enc_chn->lastFrmTimeStamp, frame->timeStamp);
		enc_chn->lastFrmTimeStamp = frame->timeStamp;
		return -1;
	}

	return 0;
}

static int encoder_get_fps_mask(EncChannel *enc_chn, IMPFrameInfo *frame)
{
    uint32_t timesofgopbyfps = 0;
    IMPEncoderRcAttr *rcAttr = &enc_chn->attr.rcAttr;

	if (frame) {
		IMPFrameInfoPriv *framePriv = frameInfo_pri(frame);
		IMPEncoderFrmRate checkedFrmRate = {0, 0};
		int maskChangeFlag1 = 0, maskChangeFlag2 = 0, maskChangeFlag3 = 0;
		if (!framePriv->i_fps_num || !framePriv->i_fps_den) {
			IMP_LOG_ERR(TAG, "invalid isp frame:framePriv->i_fps_num=%u, framePriv->i_fps_den=%u\n", framePriv->i_fps_num, framePriv->i_fps_den);
			return -1;
		}
		pthread_mutex_lock(&enc_chn->mutex);
		if (check_inframerate_valid(enc_chn, &checkedFrmRate, frame) < 0) {
			IMP_LOG_ERR(TAG, "invalid isp frame:framePriv=%u/%u, checkedFrmRate=%u/%u, inFrmRate=%u/%u\n", framePriv->i_fps_num, framePriv->i_fps_den, checkedFrmRate.frmRateNum, checkedFrmRate.frmRateDen, enc_chn->inFrmRate.frmRateNum, enc_chn->inFrmRate.frmRateDen);
			char markstr[256];
			sprintf(markstr, "echo invalid isp frame:framePriv=%u/%u, checkedFrmRate=%u/%u, inFrmRate=%u/%u >> /tmp/fpsmark.txt\n", framePriv->i_fps_num, framePriv->i_fps_den, checkedFrmRate.frmRateNum, checkedFrmRate.frmRateDen, enc_chn->inFrmRate.frmRateNum, enc_chn->inFrmRate.frmRateDen);
			pthread_mutex_unlock(&enc_chn->mutex);
			system(markstr);
			return -1;
		}
		if (!enc_chn->inFrmRate.frmRateNum || !enc_chn->inFrmRate.frmRateDen
				|| (enc_chn->inFrmRate.frmRateNum * framePriv->i_fps_den != framePriv->i_fps_num * enc_chn->inFrmRate.frmRateDen)) {
			enc_chn->inFrmRate.frmRateNum = framePriv->i_fps_num;
			enc_chn->inFrmRate.frmRateDen = framePriv->i_fps_den;
			c_reduce_fraction(&enc_chn->inFrmRate.frmRateNum, &enc_chn->inFrmRate.frmRateDen);
			maskChangeFlag1 = 1;
			IMP_LOG_INFO(TAG, "framePriv->i_fps_num=%u, framePriv->i_fps_den=%u\n", framePriv->i_fps_num, framePriv->i_fps_den);
		}

        /* here should be sure gop to be divisible by fps */
        timesofgopbyfps = rcAttr->maxGop * rcAttr->outFrmRate.frmRateDen / rcAttr->outFrmRate.frmRateNum;

		if ((maskChangeFlag1 == 1) || (rcAttr->outFrmRate.frmRateNum * enc_chn->setFrmRate.frmRateDen != enc_chn->setFrmRate.frmRateNum * rcAttr->outFrmRate.frmRateDen)) {
			if (enc_chn->setFrmRate.frmRateNum * enc_chn->inFrmRate.frmRateDen <= enc_chn->inFrmRate.frmRateNum * enc_chn->setFrmRate.frmRateDen) {
				rcAttr->outFrmRate = enc_chn->setFrmRate;
				maskChangeFlag2 = 1;
			} else if ((enc_chn->setFrmRate.frmRateNum * enc_chn->inFrmRate.frmRateDen > enc_chn->inFrmRate.frmRateNum * enc_chn->setFrmRate.frmRateDen) && (rcAttr->outFrmRate.frmRateNum * enc_chn->inFrmRate.frmRateDen != enc_chn->inFrmRate.frmRateNum * rcAttr->outFrmRate.frmRateDen)) {
				rcAttr->outFrmRate = enc_chn->inFrmRate;
				maskChangeFlag2 = 1;
			}
		}

		if (maskChangeFlag2 == 1) {
			c_reduce_fraction(&rcAttr->outFrmRate.frmRateNum, &rcAttr->outFrmRate.frmRateDen);
            if (enc_chn->attr.encAttr.enType == PT_H264) {
                i264e_rcfg_fps_param_t fps_param;
                fps_param.i_fps_num = rcAttr->outFrmRate.frmRateNum;
                fps_param.i_fps_den = rcAttr->outFrmRate.frmRateDen;
                if (i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_FPS_ID, &fps_param) < 0) {
                    IMP_LOG_ERR(TAG, "i264e_set_param I264E_RCFG_FPS_ID failed\n");
					pthread_mutex_unlock(&enc_chn->mutex);
                    return -1;
                }
            }
#ifdef CONFIG_SOC_T30
			else if (enc_chn->attr.encAttr.enType == PT_H265) {
                i265e_rcfg_fps_param_t fps_param;
                fps_param.fpsNum = rcAttr->outFrmRate.frmRateNum;
                fps_param.fpsDen = rcAttr->outFrmRate.frmRateDen;
                if (i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_FPS_ID, &fps_param) < 0) {
                    IMP_LOG_ERR(TAG, "i265e_set_param I265E_RCFG_FPS_ID failed\n");
					pthread_mutex_unlock(&enc_chn->mutex);
                    return -1;
                }
            }
#endif
		}

        if (maskChangeFlag2 || (rcAttr->maxGop != enc_chn->setMaxGop)) {
            if (maskChangeFlag2) {
                if ((timesofgopbyfps * rcAttr->outFrmRate.frmRateNum) % rcAttr->outFrmRate.frmRateDen) {
                    enc_chn->setMaxGop = (timesofgopbyfps * rcAttr->outFrmRate.frmRateNum) / rcAttr->outFrmRate.frmRateDen + 1;
                } else {
                    enc_chn->setMaxGop = (timesofgopbyfps * rcAttr->outFrmRate.frmRateNum) / rcAttr->outFrmRate.frmRateDen;
                }
            } else if (rcAttr->maxGop != enc_chn->setMaxGop) {
                if (enc_chn->setMaxGop % (rcAttr->outFrmRate.frmRateNum * rcAttr->outFrmRate.frmRateDen)) {
                    enc_chn->setMaxGop = ((enc_chn->setMaxGop / (rcAttr->outFrmRate.frmRateNum * rcAttr->outFrmRate.frmRateDen)) + 1) * (rcAttr->outFrmRate.frmRateNum * rcAttr->outFrmRate.frmRateDen);
                }
            }
			rcAttr->maxGop = enc_chn->setMaxGop;
            if (enc_chn->attr.encAttr.enType == PT_H264) {
                i264e_rcfg_gop_param_t gop_param;
                gop_param.gopsize = enc_chn->setMaxGop;
                if (i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_GOP_ID, &gop_param) < 0) {
                    IMP_LOG_ERR(TAG, "i264e set gopsize param failed, encchn\n");
					pthread_mutex_unlock(&enc_chn->mutex);
                    return -1;
                }
            }
#ifdef CONFIG_SOC_T30
			else if (enc_chn->attr.encAttr.enType == PT_H265) {
                uint32_t gopSize = enc_chn->setMaxGop;
                if (i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_GOP_ID, &gopSize) < 0) {
                    IMP_LOG_ERR(TAG, "i265e set gopsize param failed, encchn\n");
					pthread_mutex_unlock(&enc_chn->mutex);
                    return -1;
                }
            }
#endif
            maskChangeFlag3 = 1;
        }

		if ((maskChangeFlag1 == 1) || (maskChangeFlag2 == 1) || (maskChangeFlag3 == 1)) {
            enc_chn->idr_request = 1;
        }

		if ((maskChangeFlag1 == 1) || (maskChangeFlag2 == 1)) {
			if (encoder_set_fps_mask(enc_chn, enc_chn->inFrmRate, rcAttr->outFrmRate)) {
				IMP_LOG_ERR(TAG, "encoder_set_framerate failed\n");
				pthread_mutex_unlock(&enc_chn->mutex);
				return -1;
			}

			IMP_LOG_DBG(TAG, "enc_chn->index=%d, enc_chn->chnFpsMask=%llx, enc_chn->inFrmRate.frmRateNum=%u, enc_chn->inFrmRate.frmRateDen=%u, enc_chn->setFrmRate.frmRateNum=%u, enc_chn->setFrmRate.frmRateDen=%u, rcAttr->outFrmRate.frmRateNum=%u, rcAttr->outFrmRate.frmRateDen=%u\n", enc_chn->index, enc_chn->chnFpsMask, enc_chn->inFrmRate.frmRateNum, enc_chn->inFrmRate.frmRateDen, enc_chn->setFrmRate.frmRateNum, enc_chn->setFrmRate.frmRateDen, rcAttr->outFrmRate.frmRateNum, rcAttr->outFrmRate.frmRateDen);
		}
        pthread_mutex_unlock(&enc_chn->mutex);
	}

	enc_chn->chnFpsMask = (((enc_chn->chnFpsMask << 1) | (enc_chn->chnFpsMask >> (enc_chn->fpsMaskSize - 1))) & (~((uint64_t)1 << enc_chn->fpsMaskSize)));
	return (enc_chn->chnFpsMask & 0x1);
}

static inline int encoder_get_channel_qp(EncChannel *enc_chn)
{
	return enc_chn->attr.encAttr.enType == PT_H264 ? enc_chn->i264e.qp : enc_chn->i265e.qp;
}

static int do_channel_process_h264e(EncChannel *enc_chn, IMPFrameInfo *frame)
{
	i264e_pic_t *xpic = &enc_chn->i264e.xPicIn;
	EncGroup *encgrp = enc_chn->enc_group;
	Encoder *encoder = get_encoder();
	Group *group = encoder->device->groups[encgrp->index];
	imp_video_list_t *p_pad_elem_list = NULL;
	PadStreamHandler *ppadStreamHandler = NULL;
	int i = 0;

	if (encoder_get_fps_mask(enc_chn, frame) <= 0) {
		IMP_LOG_VERBOSE(TAG, "[%s]encoder_get_fps_mask is zero\n",
				group->module->name);
		return 0;
	}
	if ((enc_chn->attr.rcAttr.attrFrmUsed.enable == true) && (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode != ENC_FRM_BYPASS)) {
		if ((enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) || (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP)) {
			if (enc_chn->i264e.usedStat.used_count == 0) {
				enc_chn->i264e.usedStat.used_count = enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes;
				enc_chn->i264e.usedStat.used_frame = frame;
				if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
					if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) {
						int lockcnt = 0;
						for (lockcnt = 0; lockcnt < enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes; lockcnt++) {
							VBMLockFrameByVaddr(frame->virAddr);
							//VBMLockFrame(frame);
						}
					} else if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP) {
						VBMLockFrameByVaddr(frame->virAddr);
						//VBMLockFrame(frame);
					}
				}
			}
			if (enc_chn->i264e.usedStat.used_count > 0) {
				frame = enc_chn->i264e.usedStat.used_frame;
				if ((enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP)
						&& (enc_chn->i264e.usedStat.used_count < enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes - 1)) {
					enc_chn->i264e.usedStat.used_count--;
					xpic->i_pts = enc_chn->i264e.pts++;
					return 0;
				}
			}
		}
	} else {
		if (enc_chn->i264e.usedStat.used_count > 0) {
			if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
				if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) {
					int unlockcnt = enc_chn->i264e.usedStat.used_count;
					for (;unlockcnt > 0; unlockcnt--) {
						VBMUnlockFrameByVaddr(enc_chn->i264e.usedStat.used_frame->virAddr);
						//VBMUnLockFrame(enc_chn->i264e.usedStat.used_frame);
					}
				}
			}
			enc_chn->i264e.usedStat.used_count = 0;
			enc_chn->i264e.usedStat.used_frame = NULL;
		}
		if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf && (0 == enc_chn->direct_mode)) {
			VBMLockFrameByVaddr(frame->virAddr);
			//VBMLockFrame(frame);
		}
	}

	if (enc_chn->padData.padEnable) {
		//int freeval = 0, busyval = 0, doneval = 0;
sync_new_padFrame:
#if 0
		sem_getvalue(&enc_chn->padData.padFreeHandlerSem, &freeval);
		sem_getvalue(&enc_chn->padData.padBusyHandlerSem, &busyval);
		sem_getvalue(&enc_chn->padData.padDoneHandlerSem, &doneval);
		IMP_LOG_DBG(TAG, "%s(%d): freeval=%d,busyval=%d,doneval=%d, group->module->num_msgs_in_queue=%d,curtime=%lld\n", __func__, __LINE__, freeval, busyval, doneval, group->module->num_msgs_in_queue, IMP_System_GetTimeStamp());
#endif
		if (video_sem_timedwait(&enc_chn->padData.padBusyHandlerSem, &enc_chn->padData.padTimeSpec) < 0) {
			IMP_LOG_ERR(TAG, "%s(%d):wait padFrame failed, drop frame->timeStamp=%lld\n", __func__, __LINE__, frame->timeStamp);
			goto err_padBusyHandlerSem;
		}
		imp_video_pop_queue(&enc_chn->padData.padConstraints->busyListQueue, &enc_chn->padData.padConstraints->busyListQueue.queue, &p_pad_elem_list);
		if (p_pad_elem_list == NULL) {
			IMP_LOG_ERR(TAG, "%s(%d):enc_chn->padData.padConstraints->busyListQueue is NULL\n", __func__, __LINE__);
			goto err_busyListQueue_is_null;
		}
		imp_video_list_elem_t *p_pad_elem = container_of(p_pad_elem_list, imp_video_list_elem_t, list);
		ppadStreamHandler = (PadStreamHandler *)p_pad_elem->data;

		if (enc_chn->padData.padAttr.timeSyncEnalbe) {
			int64_t time_abs = labs(frame->timeStamp - ppadStreamHandler->padFrame->timeStamp);
			//IMP_LOG_DBG(TAG, "%s(%d):frame->timeStamp=%lld,padFrame->timeStamp=%lld, diff=%lld\n", __func__, __LINE__, frame->timeStamp, ppadStreamHandler->padFrame->timeStamp, frame->timeStamp - ppadStreamHandler->padFrame->timeStamp);
			if (time_abs <= enc_chn->padData.padAttr.padTime) {
				enc_chn->padData.padState = PAD_SYNC_SUCCESS;
			} else if (frame->timeStamp < ppadStreamHandler->padFrame->timeStamp) { //drop frame, left pad
				imp_video_push_queue_head(&enc_chn->padData.padConstraints->busyListQueue, &enc_chn->padData.padConstraints->busyListQueue.queue, p_pad_elem_list);
				sem_post(&enc_chn->padData.padBusyHandlerSem);
				enc_chn->padData.padState = PAD_SYNC_LEFT_PAD;
				IMP_LOG_DBG(TAG, "%s(%d):drop frame,left pad:frame->timeStamp=%lld,padFrame->timeStamp=%lld, diff=%lld\n", __func__, __LINE__, frame->timeStamp, ppadStreamHandler->padFrame->timeStamp, frame->timeStamp - ppadStreamHandler->padFrame->timeStamp);
				goto err_drop_frame_left_pad;
			} else if (frame->timeStamp > ppadStreamHandler->padFrame->timeStamp) { //left frame, drop pad
				IMP_LOG_DBG(TAG, "%s(%d):drop_pad,left_frame:frame->timeStamp=%lld,padFrame->timeStamp=%lld, diff=%lld\n", __func__, __LINE__, frame->timeStamp, ppadStreamHandler->padFrame->timeStamp, frame->timeStamp - ppadStreamHandler->padFrame->timeStamp);
				if (ppadStreamHandler->releaseCallback) {
					ppadStreamHandler->releaseCallback(ppadStreamHandler->padFrame, ppadStreamHandler->data);
				}
				memset(ppadStreamHandler, 0, sizeof(PadStreamHandler));
				imp_video_push_queue_tail(&enc_chn->padData.padConstraints->freeListQueue, &enc_chn->padData.padConstraints->freeListQueue.queue, p_pad_elem_list);
				sem_post(&enc_chn->padData.padFreeHandlerSem);
				enc_chn->padData.padState = PAD_SYNC_LEFT_FRAME;
				goto sync_new_padFrame;
			}
		}
	}

	if (enc_chn->inStat.need_encode_frames == 0) {
		enc_chn->inStat.start_encode_timestamp = system_gettime(RAW);
	}
	enc_chn->inStat.need_encode_frames++;
	FrameStream *cur_wr_frmstrm = get_empty_framestream_noblock(enc_chn);

	if (cur_wr_frmstrm == NULL) {
		enc_chn->inStat.drop_frames++;
		IMP_LOG_VERBOSE(TAG, "[%s][chn%d]get_empty_framestream_noblock: the bitstream buf is full\n",
					 group->module->name, enc_chn->index);
		goto err_get_empty_framestream_noblock;
	}

	if (((FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) && (2 == enc_chn->direct_mode)) ||
			((FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) && (3 == enc_chn->direct_mode))) {
		unsigned int valid_data_line;
		unsigned int isp_y_ddr_line_cnt;
		unsigned int v0_ddr_y_grp_line;
		ivdc_regrw(0x13200208, &isp_y_ddr_line_cnt, 0);
		ivdc_regrw(0x132003a8, &v0_ddr_y_grp_line, 0);
		if (((isp_y_ddr_line_cnt >> 16) & (1 << 15)) == (v0_ddr_y_grp_line & (1 << 15))) {
			valid_data_line = ((isp_y_ddr_line_cnt >> 16)&0x7fff) - (v0_ddr_y_grp_line & 0x7fff);
		} else {
			valid_data_line = ((isp_y_ddr_line_cnt >> 16)&0x7fff) + enc_chn->ivdc_mem_line - (v0_ddr_y_grp_line & 0x7fff);
		}

		if (valid_data_line > ((IMPFrameInfoPriv*)(frame->priv))->data_threshold) {
			IMP_LOG_ERR(TAG, "get_empty:valid_data_line = %d, data_threshold = %d\n", valid_data_line, ((IMPFrameInfoPriv*)(frame->priv))->data_threshold);
			Fifo_Queue(&enc_chn->wr_frameStreamFifo, cur_wr_frmstrm, AL_WAIT_FOREVER);
			sem_post(&enc_chn->wr_sem);
			goto err_get_empty_framestream_noblock;
		}
	}

	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->stat.work_done = 0;
	pthread_mutex_unlock(&enc_chn->mutex);

	if (FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) {
		enc_chn->frame_type = ((IMPFrameInfoPriv *)(frame->priv))->frame_type;
		xpic->img.plane[0] = (uint8_t *)(frame->direct_phyAddr);
		xpic->img.plane[1] = (uint8_t *)(frame->direct_phyAddr | 1 << 24);
	} else {
		if (enc_chn->padData.padEnable) {
			xpic->pad_img.plane[0] = (uint8_t*)ppadStreamHandler->padFrame->virAddr;
			xpic->pad_img.plane[1] = (uint8_t*)xpic->pad_img.plane[0] + C_ALIGN(frame->width, 16) * C_ALIGN(frame->height, 16);
			xpic->pad_img.priv = p_pad_elem_list;
		}

		xpic->img.plane[0] = (uint8_t*)frame->virAddr;
		xpic->img.plane[1] = (uint8_t*)xpic->img.plane[0] + C_ALIGN(frame->width, 16) * C_ALIGN(frame->height, 16);
	}

	/* It seems that put ncu pre-process here is fine. */
	xpic->img.is_use_ncu = 0;
	if (IS_SOC_SERIES(T20) && enc_chn->ncu_data.enabled) {
#if 0
		ncu_preprocess(frame, &enc_chn->ncu_data);
		xpic->img.is_use_ncu = 1;
		xpic->img.ncu_middate_size = enc_chn->ncu_data.data_size;
		xpic->img.ncu_middate_p = enc_chn->ncu_data.data_paddr; /* Actually we use phy-addr here. */
		xpic->img.ncu_out_p = enc_chn->ncu_data.out_frame_paddr;
	} else if (IS_SOC_SERIES(T30) && g_frame_get_sta_flag) {
		IMPFrameInfoPriv *framePriv = frameInfo_pri(frame);
		if ((frame->width == framePriv->ncuinfo.width) && (frame->height == framePriv->ncuinfo.height)) {
			xpic->img.is_use_ncu = 1;
			xpic->img.ncu_frame_info = (c_ncu_frame_info_t *)&framePriv->ncuinfo;
		}
#endif
	} else if (IS_SOC_SERIES(T21)||IS_SOC_SERIES(T23)) {
		IMPFrameInfoPriv *framePriv = frameInfo_pri(frame);
        xpic->img.is_use_ncu = framePriv->b_use_ncuinfo;
        xpic->img.ncu_frame_info = (c_ncu_frame_info_t *)&framePriv->ncuinfo;
		xpic->img.is_use_aezone = framePriv->b_use_aeinfo;
		xpic->img.ae_zone_info = (c_ae_zone_info_t *)&framePriv->ae_zone;
	}

	xpic->timestamp = frame->timeStamp;
	xpic->i_pts = enc_chn->i264e.pts++;
	memset(&xpic->extra_sei, 0, sizeof(xpic->extra_sei));

	imp_video_list_elem_t *userDataElem[NR_MAX_ENC_CHN_USERDATACNT];
	int busyUserDateElemNum = 0;
	i264e_sei_payload_t extra_sei_payloads[NR_MAX_ENC_CHN_USERDATACNT];
	memset(userDataElem, 0, sizeof(userDataElem));
	memset(extra_sei_payloads, 0, sizeof(extra_sei_payloads));
	xpic->extra_sei.payloads = extra_sei_payloads;

	if (enc_chn->i264e.userDataConstraints) {
		for (i = 0; i < enc_chn->i264e.userDataConstraints->pelemCnt; i++) {
			imp_video_list_t *p_user_data_elem_list = NULL;
			imp_video_pop_queue(&enc_chn->i264e.userDataConstraints->busyListQueue, &enc_chn->i264e.userDataConstraints->busyListQueue.queue, &p_user_data_elem_list);
			if (p_user_data_elem_list == NULL) {
				break;
			}
			userDataElem[i] = container_of(p_user_data_elem_list, imp_video_list_elem_t, list);
			if (userDataElem[i] != NULL) {

				xpic->extra_sei.payloads[xpic->extra_sei.num_payloads].payload_size = *((uint32_t *)userDataElem[i]->data);
				xpic->extra_sei.payloads[xpic->extra_sei.num_payloads].payload_type = I264E_SEI_USER_DATA_UNREGISTERED;
				xpic->extra_sei.payloads[xpic->extra_sei.num_payloads].payload = userDataElem[i]->data + 4;
				xpic->extra_sei.num_payloads++;
				busyUserDateElemNum++;
			}
		}
	}

	if (enc_chn->idr_request) {
		xpic->b_force_idr = 1;
		enc_chn->idr_request = 0;
	} else {
		xpic->b_force_idr = 0;
	}
	enc_chn->encodingFrameCnt++;

	/* user nal buffer */
	xpic->nals_buffer =(uint8_t**)&(cur_wr_frmstrm->stream_buffer);
	xpic->nals_buffer_size = enc_chn->attr.encAttr.bufSize;
	i264e_encode(enc_chn->i264e.i264eHandler, xpic);

	if (enc_chn->i264e.usedStat.used_count > 0) {
		enc_chn->i264e.usedStat.used_count--;
	}

	if (enc_chn->i264e.userDataConstraints) {
		for (i = 0; i < busyUserDateElemNum; i++) {
			if (userDataElem[i]) {
				imp_video_push_queue_tail(&enc_chn->i264e.userDataConstraints->doneListQueue, &enc_chn->i264e.userDataConstraints->doneListQueue.queue, &(userDataElem[i]->list));
			}
		}
	}

	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->i264e.qp = xpic->i_qpplus1;
	enc_chn->stat.leftPics = group_task_left(group);
	enc_chn->stat.work_done = 1;
	pthread_mutex_unlock(&enc_chn->mutex);

	return 0;

err_get_empty_framestream_noblock:
	if (enc_chn->padData.padEnable) {
		IMP_LOG_DBG(TAG, "%s(%d):drop frame and pad:frame->timeStamp=%lld,padFrame->timeStamp=%lld, diff=%lld\n", __func__, __LINE__, frame->timeStamp, ppadStreamHandler->padFrame->timeStamp, frame->timeStamp - ppadStreamHandler->padFrame->timeStamp);
		if (ppadStreamHandler->releaseCallback) {
			ppadStreamHandler->releaseCallback(ppadStreamHandler->padFrame, ppadStreamHandler->data);
		}
		memset(ppadStreamHandler, 0, sizeof(PadStreamHandler));
		imp_video_push_queue_tail(&enc_chn->padData.padConstraints->freeListQueue, &enc_chn->padData.padConstraints->freeListQueue.queue, p_pad_elem_list);
		sem_post(&enc_chn->padData.padFreeHandlerSem);
		enc_chn->padData.padState = PAD_SYNC_NONE;
	}
err_drop_frame_left_pad:
err_busyListQueue_is_null:
err_padBusyHandlerSem:
	if (enc_chn->i264e.usedStat.used_count > 0) {
		if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
			if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) {
				int unlockcnt = enc_chn->i264e.usedStat.used_count;
				for (;unlockcnt > 0; unlockcnt--) {
					VBMUnlockFrameByVaddr(enc_chn->i264e.usedStat.used_frame->virAddr);
					//VBMUnLockFrame(enc_chn->i264e.usedStat.used_frame);
				}
			} else if ((enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP) && (enc_chn->i264e.usedStat.used_count == enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes - 1)) {
				VBMUnlockFrameByVaddr(enc_chn->i264e.usedStat.used_frame->virAddr);
				//VBMUnLockFrame(enc_chn->i264e.usedStat.used_frame);
			}
		}
		enc_chn->i264e.usedStat.used_count = 0;
		enc_chn->i264e.usedStat.used_frame = NULL;
	} else if (enc_chn->i264e.usedStat.used_frame == NULL) {
		if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf && (0 == enc_chn->direct_mode)) {
			VBMUnlockFrameByVaddr(frame->virAddr);
			//VBMUnLockFrame(frame);
		}
	}

	return -1;
}

static int do_channel_process_jpege(EncChannel *enc_chn, IMPFrameInfo *frame)
{
	int i_nal;
	ijpege_pic_t *cpic = &enc_chn->jpege.cPicIn;
	ijpege_pic_t pic_out;
	ijpege_nal_t *nal;

	enc_chn->inStat.need_encode_frames++;
	FrameStream *cur_wr_frmstrm = get_empty_framestream_noblock(enc_chn);
	if (cur_wr_frmstrm == NULL) {
		enc_chn->inStat.drop_frames++;
		IMP_LOG_VERBOSE(TAG, "get_empty_framestream_noblock(%d) failed\n", enc_chn->index);
		return -1;
	}

	if (FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) {
		cpic->img.plane[0] = (uint8_t *)(frame->direct_phyAddr);
		cpic->img.plane[1] = (uint8_t *)(frame->direct_phyAddr | 1 << 24);
		enc_chn->frame_type = ((IMPFrameInfoPriv *)(frame->priv))->frame_type;
	} else {
		cpic->img.plane[0] = (uint8_t*)frame->virAddr;
		cpic->img.plane[1] = (uint8_t*)cpic->img.plane[0] + C_ALIGN(frame->width, 16) * C_ALIGN(frame->height, 16);
	}

	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->stat.work_done = 0;
	enc_chn->encodingFrameCnt++;
	pthread_mutex_unlock(&enc_chn->mutex);

	cpic->nals_buffer =(uint8_t**)&(cur_wr_frmstrm->stream_buffer);
	cpic->nals_buffer_size = enc_chn->attr.encAttr.bufSize;
	ijpege_encode(enc_chn->jpege.ijpegeHandler, &nal, &i_nal, cpic, &pic_out);

	cur_wr_frmstrm->seq = enc_chn->jpege.pts++;
	cur_wr_frmstrm->pack_count = 1;

	enc_chn->endencodeFrameCnt++;
	if (nal->i_payload > enc_chn->attr.encAttr.bufSize) {
		IMP_LOG_ERR(TAG, "Stream size=%d is out of encoder buffer size=%d",
					nal->i_payload,
					enc_chn->attr.encAttr.bufSize);
		goto err_nal_i_payload;
	}

	IMPEncoderPack *pack = &cur_wr_frmstrm->pack[0];
	pack->virAddr = (uint32_t)cur_wr_frmstrm->stream_buffer;
	pack->length = nal->i_payload;
	pack->timestamp = frame->timeStamp;
	pack->frameEnd = 1;

	if (enc_chn->frame_type == FRAME_TYPE_IVDC) {
		unsigned int ivdc_overflow = 0;
		/*获取IVDC状态，即使当前状态为OverFlow，IVDC也会输出完整帧，但是编码需要将此帧丢掉*/
		ivdc_regrw(0x1320007c, &ivdc_overflow, 0);
		if ((ivdc_overflow & 0x2<<30)) {
			release_used_framestream(enc_chn, cur_wr_frmstrm);
			pthread_mutex_lock(&enc_chn->mutex);
			enc_chn->stat.work_done = 1;
			enc_chn->endrelaseFrameCnt++;
			pthread_mutex_unlock(&enc_chn->mutex);
			IMP_LOG_DBG(TAG,"jpeg frame%d is bad\n",cur_wr_frmstrm->seq);
			return 0;
		}
	}
	Fifo_Queue(&enc_chn->rd_frameStreamFifo, cur_wr_frmstrm, AL_WAIT_FOREVER);
	mark_filled_framestream(enc_chn, cur_wr_frmstrm);

	/* Update channel stat */
	enc_chn->stat.curPacks = cur_wr_frmstrm->pack_count;

	int left_stream;
	sem_getvalue(&enc_chn->rd_sem, &left_stream);
	enc_chn->stat.leftStreamFrames = left_stream;

	enc_chn->stat.leftStreamBytes = enc_chn->attr.encAttr.bufSize - pack->length;

	EncGroup *encgrp = enc_chn->enc_group;
	Encoder *encoder = get_encoder();
	Group *group = encoder->device->groups[encgrp->index];

	enc_chn->stat.leftPics = group_task_left(group);

	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->stat.work_done = 1;
	pthread_mutex_unlock(&enc_chn->mutex);

	return 0;

err_nal_i_payload:
	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->stat.work_done = 1;
	pthread_mutex_unlock(&enc_chn->mutex);
	return -1;
}

static int i265e_release_sei(void *releasePriv, void *releaseData)
{
	imp_video_list_queue_t *doneListQueue = releasePriv;
	imp_video_list_t *list = releaseData;

	imp_video_push_queue_tail(doneListQueue, &doneListQueue->queue, list);

	return 0;
}

static int i265e_relese_frame(void *privData, void *releaseData)
{
    return VBMUnlockFrameByVaddr((uint32_t)releaseData);
}

static int do_channel_process_h265e(EncChannel *enc_chn, IMPFrameInfo *frame)
{
#ifdef CONFIG_SOC_T30
	i265e_pic_t *xpic = &enc_chn->i265e.xPicIn;
	EncGroup *encgrp = enc_chn->enc_group;
	Encoder *encoder = get_encoder();
	Group *group = encoder->device->groups[encgrp->index];
	int i = 0;

	if (encoder_get_fps_mask(enc_chn, frame) <= 0) {
		IMP_LOG_VERBOSE(TAG, "[%s]encoder_get_fps_mask is zero\n",
				group->module->name);
		return 0;
	}
	if ((enc_chn->attr.rcAttr.attrFrmUsed.enable == true) && (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode != ENC_FRM_BYPASS)) {
		if ((enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) || (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP)) {
			if (enc_chn->i265e.usedStat.used_count == 0) {
				enc_chn->i265e.usedStat.used_count = enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes;
				enc_chn->i265e.usedStat.used_frame = frame;
				if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
					if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) {
						int lockcnt = 0;
						for (lockcnt = 0; lockcnt < enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes; lockcnt++) {
							VBMLockFrameByVaddr(frame->virAddr);
							//VBMLockFrame(frame);
						}
					} else if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP) {
						VBMLockFrameByVaddr(frame->virAddr);
						//VBMLockFrame(frame);
					}
				}
			}
			if (enc_chn->i265e.usedStat.used_count > 0) {
				frame = enc_chn->i265e.usedStat.used_frame;
				if ((enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP)
						&& (enc_chn->i265e.usedStat.used_count < enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes - 1)) {
					enc_chn->i265e.usedStat.used_count--;
					xpic->pts = enc_chn->i265e.pts++;
					return 0;
				}
			}
		}
	} else {
		if (enc_chn->i265e.usedStat.used_count > 0) {
			if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
				if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) {
					int unlockcnt = enc_chn->i265e.usedStat.used_count;
					for (;unlockcnt > 0; unlockcnt--) {
						VBMUnlockFrameByVaddr(enc_chn->i265e.usedStat.used_frame->virAddr);
						//VBMUnLockFrame(enc_chn->i265e.usedStat.used_frame);
					}
				}
			}
			enc_chn->i265e.usedStat.used_count = 0;
			enc_chn->i265e.usedStat.used_frame = NULL;
		}
		if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
			VBMLockFrameByVaddr(frame->virAddr);
			//VBMLockFrame(frame);
		}
	}

	enc_chn->inStat.need_encode_frames++;
#ifdef SHOW_ENCODE_STREAM_TIME
    int b_dbg_encstream = !access("/tmp/encstream", F_OK);
    if (b_dbg_encstream) {
        IMP_LOG_DBG(TAG, "%s:chnNum=%d:send RAW time=%lld\n", __func__, enc_chn->index, system_gettime(RAW));
    }
#endif
	FrameStream *cur_wr_frmstrm = get_empty_framestream_noblock(enc_chn);
	if (cur_wr_frmstrm == NULL) {
		enc_chn->inStat.drop_frames++;
		IMP_LOG_VERBOSE(TAG, "[%s][chn%d]get_empty_framestream_noblock: the bitstream buf is full\n",
					 group->module->name, enc_chn->index);
		goto err_get_empty_framestream_noblock;
	}

	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->stat.work_done = 0;
	pthread_mutex_unlock(&enc_chn->mutex);

	xpic->img.plane[0] = (uint8_t*)frame->virAddr;
	xpic->img.plane[1] = (uint8_t*)xpic->img.plane[0] + C_ALIGN(frame->width, 16) * C_ALIGN(frame->height, 16);

	xpic->img.is_use_ncu = 0;
	if (IS_SOC_SERIES(T30) && g_frame_get_sta_flag) {
		IMPFrameInfoPriv *framePriv = frameInfo_pri(frame);
		if ((frame->width == framePriv->ncuinfo.width) && (frame->height == framePriv->ncuinfo.height)) {
			xpic->img.is_use_ncu = 1;
			xpic->img.ncu_frame_info = (c_ncu_frame_info_t *)&framePriv->ncuinfo;
		}
	}

	xpic->timestamp = frame->timeStamp;
	xpic->pts = enc_chn->i265e.pts++;
	memset(&xpic->userSEI, 0, sizeof(xpic->userSEI));

	imp_video_list_elem_t *userDataElem[NR_MAX_ENC_CHN_USERDATACNT];
	int busyUserDateElemNum = 0;
	memset(userDataElem, 0, sizeof(userDataElem));

	if (enc_chn->i265e.userDataConstraints && enc_chn->i265e.userDataConstraints->pelemCnt > 0) {
		for (i = 0; (i < enc_chn->i265e.userDataConstraints->pelemCnt) && (i < I265E_MAX_PAYLOAD_NUM); i++) {
			imp_video_list_t *p_user_data_elem_list = NULL;
			imp_video_pop_queue(&enc_chn->i265e.userDataConstraints->busyListQueue, &enc_chn->i265e.userDataConstraints->busyListQueue.queue, &p_user_data_elem_list);
			if (p_user_data_elem_list == NULL) {
				break;
			}
			userDataElem[i] = container_of(p_user_data_elem_list, imp_video_list_elem_t, list);
			if (userDataElem[i] != NULL) {
				xpic->userSEI.payloads[xpic->userSEI.numPayloads].payloadSize = *((uint32_t *)userDataElem[i]->data);
				xpic->userSEI.payloads[xpic->userSEI.numPayloads].payloadType = I265E_SEI_USER_DATA_UNREGISTERED;
				xpic->userSEI.payloads[xpic->userSEI.numPayloads].payload = userDataElem[i]->data + 4;
				xpic->userSEI.payloads[xpic->userSEI.numPayloads].releaseData = &(userDataElem[i]->list);
				xpic->userSEI.numPayloads++;
				busyUserDateElemNum++;
			}
		}
		if (busyUserDateElemNum > 0) {
			xpic->userSEI.releasePriv = &enc_chn->i265e.userDataConstraints->doneListQueue;
			xpic->userSEI.releaseFunc = i265e_release_sei;
		}
	}

	if (enc_chn->idr_request) {
		xpic->bForceIDR = 1;
		enc_chn->idr_request = 0;
	} else {
		xpic->bForceIDR = 0;
	}

	/* user nal buffer */
	xpic->nalsBuffer = (uint8_t**)&(cur_wr_frmstrm->stream_buffer);
    xpic->nalsBufSize = enc_chn->attr.encAttr.bufSize;
    xpic->releaseFunc = i265e_relese_frame;
    xpic->releaseData = (void *)frame->virAddr;
    xpic->privData = NULL;
	i265e_encode(enc_chn->i265e.i265eHandler, xpic);

	if (enc_chn->i265e.usedStat.used_count > 0) {
		enc_chn->i265e.usedStat.used_count--;
	}

	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->stat.leftPics = group_task_left(group);
	enc_chn->stat.work_done = 1;
	pthread_mutex_unlock(&enc_chn->mutex);

	return 0;

err_get_empty_framestream_noblock:
	if (enc_chn->i265e.usedStat.used_count > 0) {
		if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
			if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) {
				int unlockcnt = enc_chn->i265e.usedStat.used_count;
				for (;unlockcnt > 0; unlockcnt--) {
					VBMUnlockFrameByVaddr(enc_chn->i265e.usedStat.used_frame->virAddr);
					//VBMUnLockFrame(enc_chn->i265e.usedStat.used_frame);
				}
			} else if ((enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_SKIP) && (enc_chn->i265e.usedStat.used_count == enc_chn->attr.rcAttr.attrFrmUsed.frmUsedTimes - 1)) {
				VBMUnlockFrameByVaddr(enc_chn->i265e.usedStat.used_frame->virAddr);
				//VBMUnLockFrame(enc_chn->i265e.usedStat.used_frame);
			}
		}
		enc_chn->i265e.usedStat.used_count = 0;
		enc_chn->i265e.usedStat.used_frame = NULL;
	} else if (enc_chn->i265e.usedStat.used_frame == NULL) {
		if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
			VBMUnlockFrameByVaddr(frame->virAddr);
			//VBMUnLockFrame(frame);
		}
	}

	return -1;
#endif
}

static int do_channel_process(EncChannel *enc_chn, IMPFrameInfo *frame)
{
	if (enc_chn->attr.encAttr.enType == PT_H264) {
		return do_channel_process_h264e(enc_chn, frame);
	} else if (enc_chn->attr.encAttr.enType == PT_JPEG) {
		return do_channel_process_jpege(enc_chn, frame);
    } else if (enc_chn->attr.encAttr.enType == PT_H265) {
		return do_channel_process_h265e(enc_chn, frame);
	}

	IMP_LOG_ERR(TAG, "Playload Type %d is not support yet\n",
				enc_chn->attr.encAttr.enType);
	return -1;
}

#if SAVE_YUV_BUF
static int dump_status = 0;
static int save_open = 0;
static char *save_name = "dump.bs";
static int save_to_file(uint8_t *buf, int size)
{
	int fd = 0;
	if (save_open == 0) {
		if ((fd = open(save_name, O_WRONLY | O_APPEND | O_CREAT | O_TRUNC, 0777)) < 0) {
			printf("create %s failed\n", save_name);
			return -1;
		} else {
			save_open = 1;
		}
	} else {
		if ((fd = open(save_name, O_WRONLY | O_APPEND)) < 0) {
			printf("open %s failed\n", save_name);
			return -1;
		}
	}

	if (size != write(fd, buf, size)) {
		printf("write %s %d byte failed\n", save_name, size);
		close(fd);
		return -1;
	}
	close(fd);
	return 0;
}
#endif

uint64_t timestamp_ivdc_vpu = 0;
unsigned int overflow_cnt_vpu = 0;
unsigned int data_threshold_vpu = 0;
unsigned int ivdc_mem_line_vpu = 0;
static int frame_cnt = 0;
static int on_encoder_group_data_update(Group *group, IMPFrameInfo *frame)
{
	int i = 0;
	int j = 0;
	int ret = 0;
	int dst_width = 0;
	int dst_height = 0;
	int max_width = 0;
	int max_height = 0;
	unsigned int next_overflow_cnt = 0;
	Device *dev = get_device_of_group(group);
	Encoder *encoder = (Encoder *)device_pri(dev);
	IMPFrameInfo *resize_frame = NULL;

	EncGroup *enc_group = &encoder->encGroup[group->group_index];
	if ((2 == g_direct_mode) || (3 == g_direct_mode)) {
		pthread_mutex_lock(&g_mutex);
		for (i = 0; i < NR_MAX_ENC_CHN_IN_GROUP; i++) {
			EncChannel *enc_chn = enc_group->channel[i];
			if ((FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type)) {
				/*半直通下，helix只能串行工作。如果h264和jpeg都需要编译时，那么只编译jpeg，h264不编译。*/
				for (j = 0; j < NR_MAX_ENC_CHN_IN_GROUP; j++) {
					enc_chn = enc_group->channel[j];
					if ((enc_chn) && (enc_chn->recv_pic) && (enc_chn->stat.registered) && (enc_chn->attr.encAttr.enType == PT_JPEG)) {
						i = NR_MAX_ENC_CHN_IN_GROUP;
						break;
					}
					enc_chn = enc_group->channel[i];
				}
				i = NR_MAX_ENC_CHN_IN_GROUP;
			}
			if ((enc_chn) && (enc_chn->stat.registered) && (enc_chn->recv_pic)) {
				if (((FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) && (2 == enc_chn->direct_mode)) ||
						((FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) && (3 == enc_chn->direct_mode))) {
					if (((IMPFrameInfoPriv*)(frame->priv))->sensor_id == 0) {
						if (!(enc_chn->index == 0 || enc_chn->index == 2)){
							IMP_LOG_INFO(TAG, "Encoder Group0 sensor_id = %d, enc_chn = %d\n", ((IMPFrameInfoPriv*)(frame->priv))->sensor_id, enc_chn->index);
							pthread_mutex_unlock(&g_mutex);
							return 0;
						}
					} else if (((IMPFrameInfoPriv*)(frame->priv))->sensor_id == 1) {
						if (!(enc_chn->index == 1 || enc_chn->index == 3)){
							IMP_LOG_INFO(TAG, "Encoder Group1 sensor_id = %d, enc_chn = %d\n", ((IMPFrameInfoPriv*)(frame->priv))->sensor_id, enc_chn->index);
							pthread_mutex_unlock(&g_mutex);
							return 0;
						}
					} else if (((IMPFrameInfoPriv*)(frame->priv))->sensor_id == 2) {
						if (!(enc_chn->index == 4 || enc_chn->index == 5)) {
							IMP_LOG_INFO(TAG, "Encoder Group2 sensor_id = %d, enc_chn = %d\n", ((IMPFrameInfoPriv*)(frame->priv))->sensor_id, enc_chn->index);
							pthread_mutex_unlock(&g_mutex);
							return 0;
						}
					}

					ivdc_regrw(0x1320002c, &next_overflow_cnt, 0);
					if ((next_overflow_cnt > ((IMPFrameInfoPriv*)(frame->priv))->ivdc_overflow_cnt)) {
						IMP_LOG_ERR(TAG, "An overflow has occurred, need to drop! overflow = %d, ivdc_overflow = %d\n", next_overflow_cnt, ((IMPFrameInfoPriv*)(frame->priv))->ivdc_overflow_cnt);
						pthread_mutex_unlock(&g_mutex);
						return 0;
					}
					unsigned int isp_y_ddr_line_cnt;
					unsigned int v0_ddr_y_grp_line;
					unsigned int valid_data_line;
					ivdc_regrw(0x13200208, &isp_y_ddr_line_cnt, 0);
					ivdc_regrw(0x132003a8, &v0_ddr_y_grp_line, 0);
					if (((isp_y_ddr_line_cnt >> 16) & (1 << 15)) == (v0_ddr_y_grp_line & (1 << 15))) {
						valid_data_line = ((isp_y_ddr_line_cnt >> 16)&0x7fff) - (v0_ddr_y_grp_line & 0x7fff);
					} else {
						valid_data_line = ((isp_y_ddr_line_cnt >> 16)&0x7fff) + enc_chn->ivdc_mem_line - (v0_ddr_y_grp_line & 0x7fff);
					}

					if (valid_data_line > ((IMPFrameInfoPriv*)(frame->priv))->data_threshold) {
						IMP_LOG_ERR(TAG, "Drop valid_data_line = %d, data_threshold = %d\n", valid_data_line, ((IMPFrameInfoPriv*)(frame->priv))->data_threshold);
						pthread_mutex_unlock(&g_mutex);
						return 0;
					}

					/* 增加四个参数判断在高负载下编码流程update->vpu_start是否发生了delay导致主次摄画面切换。
					 * data_threshold_vpu:isp缓存阈值(预留参数，已无效)。
					 * overflow_cnt_vpu:ivdc发送isp_frame_start时，overflow的个数。
					 * ivdc_mem_line_vpu:ivdc的缓存大小。
					 * timestamp_ivdc_vpu:ivdc的dq时间。
					 * VPU驱动通过参数判断是否进行编码。
					 * */
					data_threshold_vpu = ((IMPFrameInfoPriv*)(frame->priv))->data_threshold;
					overflow_cnt_vpu = ((IMPFrameInfoPriv*)(frame->priv))->ivdc_overflow_cnt;
					ivdc_mem_line_vpu = enc_chn->ivdc_mem_line;
					timestamp_ivdc_vpu = frame->timeStamp_ivdc / 1000;
				}
				if ((!enc_chn->padData.padEnable)
						&& ((enc_chn->attr.encAttr.enType == PT_H264) || (enc_chn->attr.encAttr.enType == PT_JPEG))
						&& ((frame->width != enc_chn->attr.encAttr.picWidth) || (frame->height != enc_chn->attr.encAttr.picHeight))) {
					if (FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) {
						IMP_LOG_ERR(TAG, "IVDC Unsupport Encoder Scaler\n");
						pthread_mutex_unlock(&g_mutex);
						return -1;
					}
					dst_width = C_ALIGN(enc_chn->attr.encAttr.picWidth, 16);
					dst_height = C_ALIGN(enc_chn->attr.encAttr.picHeight, 16);
					if (enc_chn->resize_frame == NULL) {
						if ((enc_chn->resize_frame = malloc(sizeof(IMPFrameInfo) + sizeof(IMPFrameInfoPriv))) == NULL) {
							IMP_LOG_ERR(TAG, "malloc resize_frame failed:%s\n", strerror(errno));
							pthread_mutex_unlock(&g_mutex);
							return -1;
						}
					}
					if (enc_chn->resize_tmp_buf == NULL) {
						max_width = frame->width > dst_width ? frame->width : dst_width;
						max_height = frame->height > dst_height ? frame->height : dst_height;
						if ((enc_chn->resize_tmp_buf = (uint16_t*)malloc(sizeof(uint16_t)*(max_width * 5 + max_height * 6 + C_MAX_WH))) == NULL) {
							IMP_LOG_ERR(TAG, "malloc resize_tmp_buf failed:%s\n", strerror(errno));
							pthread_mutex_unlock(&g_mutex);
							return -1;
						}
					}
					if (enc_chn->resize_AtoA) {
						enc_chn->resize_buf = (uint8_t  *)frame->virAddr;
						enc_chn->c_resize = c_resize_c;
					} else if (enc_chn->resize_buf == NULL) {
						if ((enc_chn->resize_buf = (uint8_t*)video_vbm_malloc(enc_chn->index ,dst_width * dst_height * 3 / 2, C_VB_ALIGN)) == NULL) {
							IMP_LOG_ERR(TAG, "video_vbm_malloc resize_buf failed\n");
							pthread_mutex_unlock(&g_mutex);
							return -1;
						}
						enc_chn->c_resize = c_resize_c;
					}

					resize_frame = enc_chn->resize_frame;
					memcpy(resize_frame, frame, sizeof(IMPFrameInfo)+sizeof(IMPFrameInfoPriv));
					resize_frame->virAddr = (uint32_t)enc_chn->resize_buf;
					resize_frame->phyAddr = (uint32_t)video_vbm_virt_to_phys((intptr_t)enc_chn->resize_buf);
					resize_frame->width = enc_chn->attr.encAttr.picWidth;
					resize_frame->height = enc_chn->attr.encAttr.picHeight;
					enc_chn->c_resize((uint8_t *)frame->virAddr, (uint8_t *)resize_frame->virAddr,
							C_ALIGN(frame->width, 16), C_ALIGN(frame->height, 16),
							C_ALIGN(resize_frame->width, 16), C_ALIGN(resize_frame->height, 16),
							enc_chn->attr.encAttr.crop.enable,
							enc_chn->attr.encAttr.crop.x + enc_chn->attr.encAttr.crop.y * C_ALIGN(frame->width, 16),
							C_ALIGN(enc_chn->attr.encAttr.crop.w, 2), C_ALIGN(enc_chn->attr.encAttr.crop.h, 2),
							C_CSP_NV12, enc_chn->resize_tmp_buf);
				} else if (resize_frame == NULL) {
					resize_frame = frame;
				}

				ret += do_channel_process(enc_chn, resize_frame);
			}
		}
		pthread_mutex_unlock(&g_mutex);
	} else {
		for (i = 0; i < NR_MAX_ENC_CHN_IN_GROUP; i++) {
			EncChannel *enc_chn = enc_group->channel[i];
#if 0
			if ((FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type)) {
				if (0 == enc_chn->direct_mode) {
					IMP_LOG_ERR(TAG, "Please check the bEnableIvdc.\n");
					return -1;
				}
				/*半直通下，helix只能串行工作。如果h264和jpeg都需要编译时，那么只编译jpeg，h264不编译。*/
				for (j = 0; j < NR_MAX_ENC_CHN_IN_GROUP; j++) {
					enc_chn = enc_group->channel[j];
					if ((enc_chn) && (enc_chn->recv_pic) && (enc_chn->stat.registered) && (enc_chn->attr.encAttr.enType == PT_JPEG)) {
						i = NR_MAX_ENC_CHN_IN_GROUP;
						break;
					}
					enc_chn = enc_group->channel[i];
				}
				i = NR_MAX_ENC_CHN_IN_GROUP;
			}
#endif
			if ((enc_chn) && (enc_chn->stat.registered) && (enc_chn->recv_pic)) {
				if (FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) {
					if (0 == enc_chn->encodingFrameCnt) {
						if (frame_cnt < 3) {
							frame_cnt++;
							continue;
						} else {
							frame_cnt = 0;
						}
					}
				}
				if ((!enc_chn->padData.padEnable)
						&& ((enc_chn->attr.encAttr.enType == PT_H264) || (enc_chn->attr.encAttr.enType == PT_JPEG))
						&& ((frame->width != enc_chn->attr.encAttr.picWidth) || (frame->height != enc_chn->attr.encAttr.picHeight))) {
					if (FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) {
						IMP_LOG_ERR(TAG, "IVDC Unsupport Encoder Scaler\n");
						return -1;
					}

					dst_width = C_ALIGN(enc_chn->attr.encAttr.picWidth, 16);
					dst_height = C_ALIGN(enc_chn->attr.encAttr.picHeight, 16);
					if (enc_chn->resize_frame == NULL) {
						if ((enc_chn->resize_frame = malloc(sizeof(IMPFrameInfo) + sizeof(IMPFrameInfoPriv))) == NULL) {
							IMP_LOG_ERR(TAG, "malloc resize_frame failed:%s\n", strerror(errno));
							return -1;
						}
					}
					if (enc_chn->resize_tmp_buf == NULL) {
						max_width = frame->width > dst_width ? frame->width : dst_width;
						max_height = frame->height > dst_height ? frame->height : dst_height;
						if ((enc_chn->resize_tmp_buf = (uint16_t*)malloc(sizeof(uint16_t)*(max_width * 5 + max_height * 6 + C_MAX_WH))) == NULL) {
							IMP_LOG_ERR(TAG, "malloc resize_tmp_buf failed:%s\n", strerror(errno));
							return -1;
						}
					}
					if (enc_chn->resize_AtoA) {
						enc_chn->resize_buf = (uint8_t  *)frame->virAddr;
#if 0
						int ishassimd = is_has_simd128();
						if (ishassimd) {
							enc_chn->c_resize = c_resize_simd;
							/* Insert MXU key first. */
							mk();
						} else {
							enc_chn->c_resize = c_resize_c;
						}
#endif
						enc_chn->c_resize = c_resize_c;
					}
					else if (enc_chn->resize_buf == NULL) {
						if ((enc_chn->resize_buf = (uint8_t*)video_vbm_malloc(enc_chn->index ,dst_width * dst_height * 3 / 2, C_VB_ALIGN)) == NULL) {
							IMP_LOG_ERR(TAG, "video_vbm_malloc resize_buf failed\n");
							return -1;
						}
#if 0
						int ishassimd = is_has_simd128();
						if (ishassimd) {
							enc_chn->c_resize = c_resize_simd;
							/* Insert MXU key first. */
							mk();
						} else {
							enc_chn->c_resize = c_resize_c;
						}
						//IMP_LOG_DBG(TAG, "chnNum[%d]enter into resize:enc_chn->resize_buf=%p, frame->width=%u, enc_chn->attr.encAttr.picWidth=%u, frame->height=%u, enc_chn->attr.encAttr.picHeight=%u, func:%s\n", i, enc_chn->resize_buf, frame->width, enc_chn->attr.encAttr.picWidth, frame->height, enc_chn->attr.encAttr.picHeight, ishassimd ? "c_resize_simd" : "c_resize_c");
#endif
						enc_chn->c_resize = c_resize_c;
					}

					resize_frame = enc_chn->resize_frame;
					memcpy(resize_frame, frame, sizeof(IMPFrameInfo)+sizeof(IMPFrameInfoPriv));
					resize_frame->virAddr = (uint32_t)enc_chn->resize_buf;
					resize_frame->phyAddr = (uint32_t)video_vbm_virt_to_phys((intptr_t)enc_chn->resize_buf);
					resize_frame->width = enc_chn->attr.encAttr.picWidth;
					resize_frame->height = enc_chn->attr.encAttr.picHeight;
					enc_chn->c_resize((uint8_t *)frame->virAddr, (uint8_t *)resize_frame->virAddr,
							C_ALIGN(frame->width, 16), C_ALIGN(frame->height, 16),
							C_ALIGN(resize_frame->width, 16), C_ALIGN(resize_frame->height, 16),
							enc_chn->attr.encAttr.crop.enable,
							enc_chn->attr.encAttr.crop.x + enc_chn->attr.encAttr.crop.y * C_ALIGN(frame->width, 16),
							C_ALIGN(enc_chn->attr.encAttr.crop.w, 2), C_ALIGN(enc_chn->attr.encAttr.crop.h, 2),
							C_CSP_NV12, enc_chn->resize_tmp_buf);
#if SAVE_YUV_BUF
					if (dump_status == 0) {
						save_to_file(resize_frame->virAddr, resize_frame->width * resize_frame->height * 3 / 2);
						//IMP_LOG_DBG(TAG, "encoder save ok resize_frame->virAddr=%x, resize_frame->width=%u, resize_frame->height=%u, frame->width=%u, frame->height=%u\n", resize_frame->virAddr, resize_frame->width, resize_frame->height, frame->width, frame->height);
						dump_status = 1;
					}
#endif
				} else if (resize_frame == NULL) {
					//IMP_LOG_DBG(TAG, "enter into nomal:frame->width=%u, enc_chn->attr.encAttr.picWidth=%u, frame->height=%u, enc_chn->attr.encAttr.picHeight=%u\n", frame->width, enc_chn->attr.encAttr.picWidth, frame->height, enc_chn->attr.encAttr.picHeight);
					resize_frame = frame;
				}

				if (FRAME_TYPE_IVDC == ((IMPFrameInfoPriv*)(frame->priv))->frame_type) {
					ivdc_mem_line_vpu = enc_chn->ivdc_mem_line;
					overflow_cnt_vpu = 0;
					timestamp_ivdc_vpu = 0;
				}
				ret += do_channel_process(enc_chn, resize_frame);
			}
		}
	}

	group->for_output_data[0] = frame;

	return ret;
}

int EncoderInit(void)
{
	int ret, i;

	gEncoder = alloc_encoder();
	if (gEncoder == NULL)
		return -1;

	ret = pthread_mutex_init(&g_mutex, NULL);
	if (ret < 0) {
		IMP_LOG_ERR(TAG, "pthread_mutex_init failed\n");
		goto free;
	}

	ivdc_mmap();
	ret = encoder_init(gEncoder);
	if (ret < 0)
		goto free;

	/* g_EncChannel create instance */
	memset(g_EncChannel, 0, NR_MAX_ENC_CHN * sizeof(EncChannel));
	for (i = 0; i < NR_MAX_ENC_CHN; i++) {
		g_EncChannel[i].index = -1;	/* It's a uninitial sate*/
		g_EncChannel[i].nr_stream_buffer = 0;
	}

	if (IS_SOC_SERIES(T20)) {
		init_ispmem_info();
	}

	int dbg_enc_info(void *buf, int msize, void **arg);
	int dbg_enc_rc_s(void *buf, int msize, void **arg);
	int dbg_enc_superfrm_get(void *buf, int msize, void **arg);
	int dbg_enc_superfrm_set(void *buf, int msize, void **arg);
	int dbg_enc_rcfile_s(void *buf, int msize, void **arg);

	dsys_func_share_mem_register(FUNC_MODULE_ENC, DBG_ENC_INFO, "enc_info", dbg_enc_info);
	dsys_func_share_mem_register(FUNC_MODULE_ENC, DBG_ENC_RC_S, "enc_rc_s", dbg_enc_rc_s);
    dsys_func_share_mem_register(FUNC_MODULE_ENC, DBG_SUPERFRM_INFO, "superfrm_info", dbg_enc_superfrm_get);
	dsys_func_share_mem_register(FUNC_MODULE_ENC, DBG_SUPERFRM_INFO_S, "superfrm_set", dbg_enc_superfrm_set);
	dsys_func_share_mem_register(FUNC_MODULE_ENC, DBG_ENC_RCFILE_S, "enc_rcfile_s", dbg_enc_rcfile_s);
	return ret;
free:
	free_encoder(gEncoder);
	gEncoder = NULL;

	return -1;
}

int EncoderExit(void)
{
	if (gEncoder) {
		encoder_exit(gEncoder);
		free_encoder(gEncoder);
		ivdc_unmmap();
		pthread_mutex_destroy(&g_mutex);
		gEncoder = NULL;
	    dsys_func_unregister(FUNC_MODULE_ENC, DBG_ENC_INFO);
	    dsys_func_unregister(FUNC_MODULE_ENC, DBG_ENC_RC_S);
        dsys_func_unregister(FUNC_MODULE_ENC, DBG_SUPERFRM_INFO);
	    dsys_func_unregister(FUNC_MODULE_ENC, DBG_SUPERFRM_INFO_S);
	    dsys_func_unregister(FUNC_MODULE_ENC, DBG_ENC_RCFILE_S);
	}

	return 0;
}

int IMP_Encoder_CreateGroup(int encGroup)
{
	if (encGroup > NR_MAX_ENC_GROUPS - 1) {
		IMP_LOG_ERR(TAG, "Invalid group num%d\n", encGroup);
		return -1;
	}

	Encoder *encoder = get_encoder();
	if (encoder == NULL) {
		IMP_LOG_ERR(TAG, "Invalid Encoder\n");
		return -1;
	}

	Device *dev = encoder->device;
	char grp_name[MAX_MODULE_NAME_LEN];
	sprintf(grp_name, "%s-%d", dev->name, encGroup);

	Group *grp = create_group(DEV_ID_ENC, encGroup, grp_name,
							  on_encoder_group_data_update);
	grp->device = dev;
	grp->nr_outputs = 1;
	dev->groups[encGroup] = grp;

	encoder->encGroup[encGroup].index = encGroup;

	return 0;
}

int IMP_Encoder_DestroyGroup(int encGroup)
{
	if (encGroup > NR_MAX_ENC_GROUPS - 1) {
		IMP_LOG_ERR(TAG, "Invalid group num%d\n", encGroup);
		return -1;
	}

	Encoder *encoder = get_encoder();
	if (encoder == NULL) {
		IMP_LOG_ERR(TAG, "Encoder is not found\n");
		return -1;
	}

	Device *dev = encoder->device;
	Group *grp = dev->groups[encGroup];
	if (grp == NULL) {
		IMP_LOG_ERR(TAG, "Group-%d is not created\n");
		return -1;
	}

	destroy_group(grp, DEV_ID_ENC);
	dev->groups[encGroup] = NULL;

	return 0;
}

int update_h264_one_frmstrm(EncChannel *enc_chn)
{
	i264e_pic_t *pic_in = NULL, *pic_out = NULL;
	i264e_nal_t *nals;
	int total_bs_size = 0, i = 0, nnal = 0;
	void *bshandler = NULL, *thandler = NULL;
	int ret = -1;
	if ((ret = i264e_get_bitstream(enc_chn->i264e.i264eHandler, &nals, &nnal, &pic_in,
					&pic_out, &bshandler, &thandler)) < 0) {
		IMP_LOG_ERR(TAG, "h264 get_bitstream failed");
		goto err_i264e_get_bitstream;
	}
	enc_chn->endencodeFrameCnt++;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf && (0 == enc_chn->direct_mode)) {
		VBMUnlockFrameByVaddr((uint32_t)pic_in->img.plane[0]);
	}

	if (enc_chn->padData.padEnable) {
		imp_video_list_t *p_pad_elem_list = (imp_video_list_t *)pic_out->pad_img.priv;
		imp_video_list_elem_t *p_pad_elem = container_of(p_pad_elem_list, imp_video_list_elem_t, list);
		PadStreamHandler *ppadStreamHandler = (PadStreamHandler *)p_pad_elem->data;
		if (ppadStreamHandler->releaseCallback) {
			ppadStreamHandler->releaseCallback(ppadStreamHandler->padFrame, ppadStreamHandler->data);
		}
		memset(ppadStreamHandler, 0, sizeof(PadStreamHandler));
		imp_video_push_queue_tail(&enc_chn->padData.padConstraints->freeListQueue, &enc_chn->padData.padConstraints->freeListQueue.queue, p_pad_elem_list);
		sem_post(&enc_chn->padData.padFreeHandlerSem);
	}

	if (nnal > NR_MAX_PACK_IN_FRAME) {
		IMP_LOG_ERR(TAG, "%s:Err:nal count=%d is out of NR_MAX_PACK_IN_FRAME=%d\n",
					__func__, nnal, NR_MAX_PACK_IN_FRAME);
		goto err_outof_max_pack;
	}

	FrameStream *cur_wr_frmstrm = container_of((void** )pic_out->nals_buffer, FrameStream, stream_buffer);
	if (cur_wr_frmstrm == NULL) {
		IMP_LOG_ERR(TAG, "the cur_wr_frmstrm is NULL, nnal=%d, NR_MAX_PACK_IN_FRAME=%d\n",
					nnal, NR_MAX_PACK_IN_FRAME);
		goto err_empty_cur_wr_frmstrm;
	}

	enc_chn->i264e.xPicOut = *pic_out;
	cur_wr_frmstrm->seq = pic_out->i_pts;
	cur_wr_frmstrm->pack_count = nnal;
	cur_wr_frmstrm->refType = pic_out->fsktype;

	for (i = 0; i < nnal; i++) {
		IMPEncoderPack *pack = &cur_wr_frmstrm->pack[i];
		pack->virAddr = (uint32_t)nals[i].p_payload;
		pack->length = nals[i].i_payload;
		if (pack->length == 0) {
			i264e_release_bitstream(enc_chn->i264e.i264eHandler, bshandler, thandler);
			release_used_framestream(enc_chn, cur_wr_frmstrm);
			pthread_mutex_lock(&enc_chn->mutex);
			enc_chn->endrelaseFrameCnt++;
			pthread_mutex_unlock(&enc_chn->mutex);
			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

			return 0;
		}
		pack->dataType.h264Type = nals[i].i_type;
		pack->timestamp = pic_out->timestamp;
		if (i == (nnal - 1)) {
			pack->frameEnd = 1;
			total_bs_size = (intptr_t)nals[i].p_payload - (intptr_t)cur_wr_frmstrm->stream_buffer + nals[i].i_payload;
		} else {
			pack->frameEnd = 0;
		}
	}

	if (FRAME_TYPE_IVDC == enc_chn->frame_type) {
		unsigned int ivdc_overflow = 0;
		/*获取IVDC状态，即使当前状态为OverFlow，IVDC也会输出完整的错帧，编码需要将此帧丢掉*/
		/*因为丢帧导致参考帧序列出错，所以要申请IDR帧重新开始*/
		/*高速模式下<0x07C bit30>checksum不可用*/
		ivdc_regrw(0x1320007c, &ivdc_overflow, 0);
		if (ivdc_overflow & (0x2<<30)) {
			enc_chn->idr_request = 1;
			enc_chn->ivdc_reset_flag = 1;

			i264e_release_bitstream(enc_chn->i264e.i264eHandler, bshandler, thandler);
			release_used_framestream(enc_chn, cur_wr_frmstrm);
			pthread_mutex_lock(&enc_chn->mutex);
			enc_chn->endrelaseFrameCnt++;
			pthread_mutex_unlock(&enc_chn->mutex);
			IMP_LOG_DBG(TAG, "xh264 frame%d is bad\n",cur_wr_frmstrm->seq);
			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

			return 0;
		}

		/*上一帧丢掉后，需要判断当前帧是否为I帧，如果是P帧则丢掉*/
		if (enc_chn->ivdc_reset_flag == 1) {
			if (cur_wr_frmstrm->pack[cur_wr_frmstrm->pack_count - 1].dataType.h264Type == IMP_H264_NAL_SLICE_IDR) {
				enc_chn->ivdc_reset_flag = 0;
			} else {
				enc_chn->idr_request = 1;
				enc_chn->ivdc_reset_flag = 1;

				i264e_release_bitstream(enc_chn->i264e.i264eHandler, bshandler, thandler);
				release_used_framestream(enc_chn, cur_wr_frmstrm);
				pthread_mutex_lock(&enc_chn->mutex);
				enc_chn->endrelaseFrameCnt++;
				pthread_mutex_unlock(&enc_chn->mutex);
				pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

				return 0;
			}
		}
	}

	Fifo_Queue(&enc_chn->rd_frameStreamFifo, cur_wr_frmstrm, AL_WAIT_FOREVER);
	i264e_release_bitstream(enc_chn->i264e.i264eHandler, bshandler, thandler);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

	mark_filled_framestream(enc_chn, cur_wr_frmstrm);

	/* Update channel stat */
	enc_chn->stat.curPacks = cur_wr_frmstrm->pack_count;

	int left_stream;
	sem_getvalue(&enc_chn->rd_sem, &left_stream);
	enc_chn->stat.leftStreamFrames = left_stream;
	enc_chn->stat.leftStreamBytes = enc_chn->attr.encAttr.bufSize - total_bs_size;

	return 0;

err_empty_cur_wr_frmstrm:
err_outof_max_pack:
	i264e_release_bitstream(enc_chn->i264e.i264eHandler, bshandler, thandler);
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
err_i264e_get_bitstream:
	return -1;
}

int update_h265_one_frmstrm(EncChannel *enc_chn)
{
#ifdef CONFIG_SOC_T30
	i265e_pic_t *pic_in = NULL, *pic_out = NULL;
	i265e_nal_t *nals;
	int total_bs_size = 0, i = 0, nnal = 0;
	void *bshandler = NULL, *thandler = NULL;
	int ret = -1;

	if ((ret = i265e_get_bitstream(enc_chn->i265e.i265eHandler, &nals, &nnal, &pic_in,
					&pic_out, &bshandler, &thandler)) < 0) {
		IMP_LOG_ERR(TAG, "h265 get_bitstream failed");
		goto err_i265e_get_bitstream;
	}

#if 0
	if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
		VBMUnlockFrameByVaddr((uint32_t)pic_in->img.plane[0]);
	}
#endif

    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	if (nnal > NR_MAX_PACK_IN_FRAME) {
		IMP_LOG_ERR(TAG, "%s:Err:nal count=%d is out of NR_MAX_PACK_IN_FRAME=%d\n",
					__func__, nnal, NR_MAX_PACK_IN_FRAME);
		goto err_outof_max_pack;
	}
	FrameStream *cur_wr_frmstrm = container_of((void** )pic_out->nalsBuffer, FrameStream, stream_buffer);
	if (cur_wr_frmstrm == NULL) {
		IMP_LOG_ERR(TAG, "the cur_wr_frmstrm is NULL, nnal=%d, NR_MAX_PACK_IN_FRAME=%d\n",
					nnal, NR_MAX_PACK_IN_FRAME);
		goto err_empty_cur_wr_frmstrm;
	}
	enc_chn->i265e.xPicOut = *pic_out;
	cur_wr_frmstrm->seq = pic_out->pts;
	cur_wr_frmstrm->pack_count = nnal;
	cur_wr_frmstrm->refType = pic_out->fsktype;

	for (i = 0; i < nnal; i++) {
		IMPEncoderPack *pack = &cur_wr_frmstrm->pack[i];
		pack->virAddr = (uint32_t)nals[i].p_payload;
		pack->length = nals[i].i_payload;
		pack->dataType.h265Type = nals[i].i_type;
		pack->timestamp = pic_out->timestamp;
		if (i == (nnal - 1)) {
			pack->frameEnd = 1;
			total_bs_size = (intptr_t)nals[i].p_payload - (intptr_t)cur_wr_frmstrm->stream_buffer + nals[i].i_payload;
		} else {
			pack->frameEnd = 0;
		}
	}

	i265e_release_bitstream(enc_chn->i265e.i265eHandler, bshandler, thandler);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

	mark_filled_framestream(enc_chn, cur_wr_frmstrm);

	/* Update channel stat */
	enc_chn->stat.curPacks = cur_wr_frmstrm->pack_count;
	enc_chn->i265e.qp = pic_out->qp;

	int left_stream;
	sem_getvalue(&enc_chn->rd_sem, &left_stream);
	enc_chn->stat.leftStreamFrames = left_stream;
	enc_chn->stat.leftStreamBytes = enc_chn->attr.encAttr.bufSize - total_bs_size;

	return 0;

err_empty_cur_wr_frmstrm:
err_outof_max_pack:
	i265e_release_bitstream(enc_chn->i265e.i265eHandler, bshandler, thandler);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
err_i265e_get_bitstream:
	return -1;
#else
	return 0;
#endif
}

void *update_frmstrm(void *arg)
{
	EncChannel *enc_chn = (EncChannel *)arg;
	char thread_name[64];
	int ret = 0;
    void (*get_bitstream_cleanup_route)(void *);
    void *get_bitstream_cleanup_route_args = NULL;

	sprintf(thread_name, "ENC(%d)-%s", enc_chn->index, __func__);
	prctl(PR_SET_NAME, (unsigned long)thread_name);

    if (enc_chn->attr.encAttr.enType == PT_H264) {
        get_bitstream_cleanup_route = i264e_get_bitstream_cleanup_route;
        get_bitstream_cleanup_route_args = enc_chn->i264e.i264eHandler;
#ifdef CONFIG_SOC_T30
    } else if (enc_chn->attr.encAttr.enType == PT_H265) {
        get_bitstream_cleanup_route = i265e_get_bitstream_cleanup_route;
        get_bitstream_cleanup_route_args = enc_chn->i265e.i265eHandler;
#endif
    }

    if ((enc_chn->attr.encAttr.enType == PT_H264) || (enc_chn->attr.encAttr.enType == PT_H265))
        pthread_cleanup_push(get_bitstream_cleanup_route, get_bitstream_cleanup_route_args);


	while ((ret >= 0) && (enc_chn)) {
		if (enc_chn->stat.registered) {
            if (enc_chn->attr.encAttr.enType == PT_H264) {
                ret = update_h264_one_frmstrm(enc_chn);
            } else if (enc_chn->attr.encAttr.enType == PT_H265) {
                ret = update_h265_one_frmstrm(enc_chn);
            } else {
                IMP_LOG_ERR(TAG, "unsupport encType=%d\n", __func__, enc_chn->attr.encAttr.enType);
                break;
            }
            pthread_testcancel();
		} else {
			usleep(20000);
		}
	}

    if ((enc_chn->attr.encAttr.enType == PT_H264) || (enc_chn->attr.encAttr.enType == PT_H265))
        pthread_cleanup_pop(0);

	return (void *)ret;
}

static void dump_encoder_chn_attr(int encChn, const IMPEncoderCHNAttr *attr, char *func, int line)
{
	IMP_LOG_DBG(TAG, "-----------------------%s(%d) start---------------------------------------\n", func, line);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.enType = %d\n", encChn, attr->encAttr.enType);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.bufSize = %d\n", encChn, attr->encAttr.bufSize);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.profile = %d\n", encChn, attr->encAttr.profile);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.picWidth = %d\n", encChn, attr->encAttr.picWidth);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.picHeight = %d\n", encChn, attr->encAttr.picHeight);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.crop.enable = %d\n", encChn, attr->encAttr.crop.enable);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.crop.x = %d\n", encChn, attr->encAttr.crop.x);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.crop.y = %d\n", encChn, attr->encAttr.crop.y);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.crop.w = %d\n", encChn, attr->encAttr.crop.w);
	IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.crop.h = %d\n", encChn, attr->encAttr.crop.h);
	if (attr->encAttr.enType == PT_H264) {
		IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.userData.maxUserDataCnt = %d\n", encChn, attr->encAttr.userData.maxUserDataCnt);
		IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.userData.maxUserDataSize = %d\n", encChn, attr->encAttr.userData.maxUserDataSize);
        IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.outFrmRate.frmRateNum = %d\n", encChn, attr->rcAttr.outFrmRate.frmRateNum);
        IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.outFrmRate.frmRateDen = %d\n", encChn, attr->rcAttr.outFrmRate.frmRateDen);
        IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.maxGop = %d\n", encChn, attr->rcAttr.maxGop);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.rcMode = %d\n", encChn, attr->rcAttr.attrRcMode.rcMode);
		if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_FIXQP) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264FixQp.qp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264FixQp.qp);
		} else if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_CBR) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.maxQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.maxQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.minQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.minQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.outBitRate = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.outBitRate);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.iBiasLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.iBiasLvl);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.frmQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.frmQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.gopQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.gopQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.adaptiveMode = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.adaptiveMode);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Cbr.gopRelation = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Cbr.gopRelation);
		} else if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_VBR) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Vbr.maxQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Vbr.maxQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Vbr.minQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Vbr.minQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Vbr.staticTime = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Vbr.staticTime);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Vbr.maxBitRate = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Vbr.maxBitRate);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Vbr.changePos = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Vbr.changePos);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Vbr.frmQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Vbr.frmQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Vbr.gopQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Vbr.gopQPStep);
		} else if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_SMART) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.maxQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.maxQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.minQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.minQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.staticTime = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.staticTime);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.maxBitRate = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.maxBitRate);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.iBiasLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.iBiasLvl);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.changePos = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.changePos);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.qualityLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.qualityLvl);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.frmQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.frmQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.gopQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.gopQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH264Smart.gopRelation = %d\n", encChn, attr->rcAttr.attrRcMode.attrH264Smart.gopRelation);
		}
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrFrmUsed.enable = %d\n", encChn, attr->rcAttr.attrFrmUsed.enable);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrFrmUsed.frmUsedMode = %d\n", encChn, attr->rcAttr.attrFrmUsed.frmUsedMode);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrFrmUsed.frmUsedTimes = %d\n", encChn, attr->rcAttr.attrFrmUsed.frmUsedTimes);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.enable = %d\n", encChn, attr->rcAttr.attrDenoise.enable);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.dnType = %d\n", encChn, attr->rcAttr.attrDenoise.dnType);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.dnIQp = %d\n", encChn, attr->rcAttr.attrDenoise.dnIQp);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.dnPQp = %d\n", encChn, attr->rcAttr.attrDenoise.dnPQp);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.skipType = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.skipType);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.m = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.m);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.n = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.n);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.maxSameSceneCnt = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.maxSameSceneCnt);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.bEnableScenecut = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.bEnableScenecut);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.bBlackEnhance = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.bBlackEnhance);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.maxHSkipType = %d\n", encChn, attr->rcAttr.attrHSkip.maxHSkipType);
    } else if (attr->encAttr.enType == PT_H265) {
		IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.userData.maxUserDataCnt = %d\n", encChn, attr->encAttr.userData.maxUserDataCnt);
		IMP_LOG_DBG(TAG, "enc[%d]attr->encAttr.userData.maxUserDataSize = %d\n", encChn, attr->encAttr.userData.maxUserDataSize);
        IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.outFrmRate.frmRateNum = %d\n", encChn, attr->rcAttr.outFrmRate.frmRateNum);
        IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.outFrmRate.frmRateDen = %d\n", encChn, attr->rcAttr.outFrmRate.frmRateDen);
        IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.maxGop = %d\n", encChn, attr->rcAttr.maxGop);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.rcMode = %d\n", encChn, attr->rcAttr.attrRcMode.rcMode);
		if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_FIXQP) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265FixQp.qp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265FixQp.qp);
		} else if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_CBR) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Cbr.maxQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Cbr.maxQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Cbr.minQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Cbr.minQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Cbr.outBitRate = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Cbr.outBitRate);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Cbr.iBiasLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Cbr.iBiasLvl);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Cbr.frmQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Cbr.frmQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Cbr.gopQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Cbr.gopQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Cbr.flucLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Cbr.flucLvl);
		} else if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_VBR) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.maxQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.maxQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.minQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.minQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.staticTime = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.staticTime);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.maxBitRate = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.maxBitRate);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.changePos = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.changePos);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.frmQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.frmQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.gopQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.gopQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Vbr.flucLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Vbr.flucLvl);
		} else if (attr->rcAttr.attrRcMode.rcMode == ENC_RC_MODE_SMART) {
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.maxQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.maxQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.minQp = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.minQp);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.staticTime = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.staticTime);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.maxBitRate = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.maxBitRate);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.iBiasLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.iBiasLvl);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.changePos = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.changePos);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.qualityLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.qualityLvl);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.frmQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.frmQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.gopQPStep = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.gopQPStep);
			IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrRcMode.attrH265Smart.flucLvl = %d\n", encChn, attr->rcAttr.attrRcMode.attrH265Smart.flucLvl);
		}
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrFrmUsed.enable = %d\n", encChn, attr->rcAttr.attrFrmUsed.enable);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrFrmUsed.frmUsedMode = %d\n", encChn, attr->rcAttr.attrFrmUsed.frmUsedMode);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrFrmUsed.frmUsedTimes = %d\n", encChn, attr->rcAttr.attrFrmUsed.frmUsedTimes);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.enable = %d\n", encChn, attr->rcAttr.attrDenoise.enable);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.dnType = %d\n", encChn, attr->rcAttr.attrDenoise.dnType);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.dnIQp = %d\n", encChn, attr->rcAttr.attrDenoise.dnIQp);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrDenoise.dnPQp = %d\n", encChn, attr->rcAttr.attrDenoise.dnPQp);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.skipType = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.skipType);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.m = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.m);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.n = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.n);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.maxSameSceneCnt = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.maxSameSceneCnt);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.bEnableScenecut = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.bEnableScenecut);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.hSkipAttr.bBlackEnhance = %d\n", encChn, attr->rcAttr.attrHSkip.hSkipAttr.bBlackEnhance);
		IMP_LOG_DBG(TAG, "enc[%d]attr->rcAttr.attrHSkip.maxHSkipType = %d\n", encChn, attr->rcAttr.attrHSkip.maxHSkipType);
	}
	IMP_LOG_DBG(TAG, "-----------------------%s(%d) end---------------------------------------\n", func, line);
}

static int channel_i264e_encoder_init(EncChannel *enc_chn)
{
	IMPEncoderCHNAttr *chn_attr = &enc_chn->attr;
	i264e_t *i264e_handler;
	i264e_param_t i264e_param;

	i264e_param_default(&i264e_param);

#ifdef CONFIG_SOC_M200
	i264e_param.soc = C_M200;
#else
	if (IS_SOC_SERIES(T10)) {
		i264e_param.soc = C_T10;
		i264e_param.b_use_ncu = 0;
	} else if (IS_SOC_SERIES(T20)) {
		i264e_param.soc = C_T20;
		i264e_param.b_use_ncu = 1;
	} else if (IS_SOC_SERIES(T30)){
		i264e_param.soc = C_T30;
		i264e_param.b_use_ncu = 0;
	}else if (IS_SOC_SERIES(T21)){
		i264e_param.soc = C_T21;
		i264e_param.b_use_ncu = 0;
	}else if (IS_SOC_SERIES(T23)){
		i264e_param.soc = C_T23;
		i264e_param.b_use_ncu = 0;
	}
	else {
		IMP_LOG_ERR(TAG, "soc type (%d) not support yet\n", get_cpu_id());
		return -1;
	}
#endif
	i264e_param.index = enc_chn->index;
	i264e_param.i_threads = 1;
	i264e_param.b_open_coop = 0;
	i264e_param.i_devid = -1;
	/* profile value: 66-PROFILE_BASELINE, 77-PROFILE_MAIN, 100-PROFILE_HIGH, this should be same to protocol as to i264e_set.h */
	i264e_param.i_profile = (chn_attr->encAttr.profile == 0) ? 66 : ((chn_attr->encAttr.profile == 1) ? 77 : ((chn_attr->encAttr.profile == 2) ? 100 : -1));
	i264e_param.hskip.i_skip_type = chn_attr->rcAttr.attrHSkip.hSkipAttr.skipType;
	i264e_param.hskip.m = chn_attr->rcAttr.attrHSkip.hSkipAttr.m;
	i264e_param.hskip.n = chn_attr->rcAttr.attrHSkip.hSkipAttr.n;
	i264e_param.hskip.max_same_scenecnt = chn_attr->rcAttr.attrHSkip.hSkipAttr.maxSameSceneCnt;
	i264e_param.hskip.b_enable_scenecut = chn_attr->rcAttr.attrHSkip.hSkipAttr.bEnableScenecut;
	i264e_param.hskip.b_black_enhance = chn_attr->rcAttr.attrHSkip.hSkipAttr.bBlackEnhance;
	if ((chn_attr->rcAttr.attrHSkip.hSkipAttr.skipType >= IMP_Encoder_STYPE_N4X)
			|| (chn_attr->rcAttr.attrHSkip.maxHSkipType >= IMP_Encoder_STYPE_N4X)) {
		i264e_param.i_max_skip_type = chn_attr->rcAttr.attrHSkip.maxHSkipType = IMP_Encoder_STYPE_H1M_TRUE;
	}
	i264e_param.i_width = chn_attr->encAttr.picWidth;
	i264e_param.i_height = chn_attr->encAttr.picHeight;

	i264e_param.ckmalloc = video_vbm_malloc;
	i264e_param.ckfree = video_vbm_free;
	i264e_param.ckvirt_to_phys = video_vbm_virt_to_phys;
	i264e_param.ckphys_to_virt = video_vbm_phys_to_virt;
	i264e_param.b_tlb = 0;
	i264e_param.b_use_phy = 1;

	i264e_param.b_user_nalbuffer = 1;
	i264e_param.b_buf_share = !!enc_chn->b_enable_bufshare;
	i264e_param.i_csp = C_CSP_NV12; /* Fixed input format */
	i264e_param.b_use_dn = chn_attr->rcAttr.attrDenoise.enable;
	if (!chn_attr->rcAttr.attrDenoise.enable) {
		i264e_param.denoise.i_dn_type = chn_attr->rcAttr.attrDenoise.dnType = I264E_DN_NONE;
	} else {
		i264e_param.denoise.i_dn_type = chn_attr->rcAttr.attrDenoise.dnType;
	}
	i264e_param.denoise.i_itype_qp = chn_attr->rcAttr.attrDenoise.dnIQp;
	i264e_param.denoise.i_ptype_qp = chn_attr->rcAttr.attrDenoise.dnPQp;
	/* Parvate tlb */
	i264e_param.private_tlb_flag = enc_chn->padData.padEnable;
	i264e_param.private_tlb_vbase = enc_chn->padData.padTlb.info.vaddr;
	i264e_param.private_tlb_pbase = enc_chn->padData.padTlb.info.paddr;
	i264e_param.b_fisheye = enc_chn->b_fisheye;

	if (chn_attr->encAttr.userData.maxUserDataCnt > 0) {
		chn_attr->encAttr.userData.maxUserDataCnt = c_clip3(chn_attr->encAttr.userData.maxUserDataCnt, 0, NR_MAX_ENC_CHN_USERDATACNT);
		chn_attr->encAttr.userData.maxUserDataSize = c_clip3(chn_attr->encAttr.userData.maxUserDataSize, 16, NR_MAX_ENC_CHN_USERDATASIZE);
		enc_chn->i264e.userDataConstraints = imp_video_container_init(chn_attr->encAttr.userData.maxUserDataCnt, chn_attr->encAttr.userData.maxUserDataSize + 20);
		if (enc_chn->i264e.userDataConstraints == NULL) {
			IMP_LOG_DBG(TAG, "%s(%d):imp_video_container_init failed\n", __func__, __LINE__);
			return -1;
		}
	}

	switch (chn_attr->rcAttr.attrRcMode.rcMode) {
	case ENC_RC_MODE_FIXQP:
		i264e_param.rc.i_rc_method = I264E_RC_CQP;
		i264e_param.rc.i_qp_constant = chn_attr->rcAttr.attrRcMode.attrH264FixQp.qp;
		break;
	case ENC_RC_MODE_CBR:
		i264e_param.rc.i_rc_method = I264E_RC_CBR;
		i264e_param.rc.i_bitrate = chn_attr->rcAttr.attrRcMode.attrH264Cbr.outBitRate;
		i264e_param.rc.i_qp_min = chn_attr->rcAttr.attrRcMode.attrH264Cbr.minQp;
		i264e_param.rc.i_qp_max = chn_attr->rcAttr.attrRcMode.attrH264Cbr.maxQp;
		i264e_param.rc.i_biaslvl = chn_attr->rcAttr.attrRcMode.attrH264Cbr.iBiasLvl;
        i264e_param.rc.i_qp_step = chn_attr->rcAttr.attrRcMode.attrH264Cbr.frmQPStep;
		i264e_param.rc.i_gop_qp_step = chn_attr->rcAttr.attrRcMode.attrH264Cbr.gopQPStep;
		i264e_param.rc.b_adaptive_mode = chn_attr->rcAttr.attrRcMode.attrH264Cbr.adaptiveMode;
		i264e_param.rc.b_gop_relation = chn_attr->rcAttr.attrRcMode.attrH264Cbr.gopRelation;
		break;
	case ENC_RC_MODE_VBR:
		i264e_param.rc.i_rc_method = I264E_RC_VBR;
		i264e_param.rc.i_qp_min = chn_attr->rcAttr.attrRcMode.attrH264Vbr.minQp;
		i264e_param.rc.i_qp_max = chn_attr->rcAttr.attrRcMode.attrH264Vbr.maxQp;
		i264e_param.rc.i_static_time = chn_attr->rcAttr.attrRcMode.attrH264Vbr.staticTime;
		i264e_param.rc.i_max_bitrate = chn_attr->rcAttr.attrRcMode.attrH264Vbr.maxBitRate;
		i264e_param.rc.i_biaslvl = chn_attr->rcAttr.attrRcMode.attrH264Vbr.iBiasLvl;
		i264e_param.rc.i_change_pos = chn_attr->rcAttr.attrRcMode.attrH264Vbr.changePos;
		i264e_param.rc.i_quality_level = chn_attr->rcAttr.attrRcMode.attrH264Vbr.qualityLvl;
        i264e_param.rc.i_qp_step = chn_attr->rcAttr.attrRcMode.attrH264Vbr.frmQPStep;
		i264e_param.rc.i_gop_qp_step = chn_attr->rcAttr.attrRcMode.attrH264Vbr.gopQPStep;
		i264e_param.rc.b_gop_relation = chn_attr->rcAttr.attrRcMode.attrH264Vbr.gopRelation;
		break;
	case ENC_RC_MODE_SMART:
		i264e_param.rc.i_rc_method = I264E_RC_SMART;
		i264e_param.rc.i_qp_min = chn_attr->rcAttr.attrRcMode.attrH264Smart.minQp;
		i264e_param.rc.i_qp_max = chn_attr->rcAttr.attrRcMode.attrH264Smart.maxQp;
		i264e_param.rc.i_static_time = chn_attr->rcAttr.attrRcMode.attrH264Smart.staticTime;
		i264e_param.rc.i_max_bitrate = chn_attr->rcAttr.attrRcMode.attrH264Smart.maxBitRate;
		i264e_param.rc.i_biaslvl = chn_attr->rcAttr.attrRcMode.attrH264Smart.iBiasLvl;
		i264e_param.rc.i_change_pos = chn_attr->rcAttr.attrRcMode.attrH264Smart.changePos;
		i264e_param.rc.i_quality_level = chn_attr->rcAttr.attrRcMode.attrH264Smart.qualityLvl;
        i264e_param.rc.i_qp_step = chn_attr->rcAttr.attrRcMode.attrH264Smart.frmQPStep;
		i264e_param.rc.i_gop_qp_step = chn_attr->rcAttr.attrRcMode.attrH264Smart.gopQPStep;
		i264e_param.rc.b_gop_relation = chn_attr->rcAttr.attrRcMode.attrH264Smart.gopRelation;
		break;
	default:
		IMP_LOG_ERR(TAG, "H264 RC Mode %d not support yet\n", chn_attr->rcAttr.attrRcMode.rcMode);
		return -1;
	}

    i264e_param.i_gop = chn_attr->rcAttr.maxGop;
    c_reduce_fraction(&chn_attr->rcAttr.outFrmRate.frmRateNum, &chn_attr->rcAttr.outFrmRate.frmRateDen);
    i264e_param.i_fps_num = chn_attr->rcAttr.outFrmRate.frmRateNum;
    i264e_param.i_fps_den = chn_attr->rcAttr.outFrmRate.frmRateDen;
    if (i264e_param.i_fps_num == 0 || i264e_param.i_fps_den == 0) {
        i264e_param.i_fps_num = chn_attr->rcAttr.outFrmRate.frmRateNum = 25;
        i264e_param.i_fps_den = chn_attr->rcAttr.outFrmRate.frmRateDen = 1;
    }
    if ((i264e_param.i_gop * i264e_param.i_fps_den) % i264e_param.i_fps_num) {
        i264e_param.i_gop = (i264e_param.i_gop / i264e_param.i_fps_num + 1) * i264e_param.i_fps_num;
    }
    chn_attr->rcAttr.maxGop = i264e_param.i_gop;

	i264e_param.superFrm.iframe_bits_thresd = (chn_attr->encAttr.bufSize - 8192 - 64 * 2) * 8;

	if (access("/tmp/encattr", F_OK) == 0) {
		dump_encoder_chn_attr(enc_chn->index, chn_attr, __func__, __LINE__);
	}

	i264e_handler = i264e_init(&i264e_param);
	if (i264e_handler == NULL) {
		IMP_LOG_ERR(TAG, "Encoder open error\n");
		return -1;
	}

	i264e_pic_t *i264e_pic = &enc_chn->i264e.xPicIn;
	memset(i264e_pic, 0, sizeof(i264e_pic_t));

	/* Init i264e picture */
	i264e_pic->img.i_csp = i264e_param.i_csp;
	i264e_pic->img.i_plane = 2;
	i264e_pic->img.i_stride[0] = i264e_pic->img.i_stride[1] = C_ALIGN(i264e_param.i_width, 16);
	i264e_pic->img.i_lines[0] = C_ALIGN(i264e_param.i_height, 16);
	i264e_pic->img.i_lines[1] = C_ALIGN(i264e_param.i_height, 16) / 2;
	i264e_pic->img.is_vir = 0;

	enc_chn->i264e.i264eHandler = i264e_handler;
	enc_chn->i264e.i264eParam = i264e_param;
	enc_chn->i264e.pts = 0;
	enc_chn->i264e.qp = i264e_param.rc.i_qp_constant;

	enc_chn->i264e.usedStat.used_count = 0;
	enc_chn->i264e.usedStat.used_frame = NULL;

	enc_chn->i264e.demask_cnt = 0;
	enc_chn->i264e.created_align_skip_type = i264e_param.i_max_skip_type;

	enc_chn->setFrmRate.frmRateNum = i264e_param.i_fps_num;
	enc_chn->setFrmRate.frmRateDen = i264e_param.i_fps_den;
	enc_chn->setMaxGop = i264e_param.i_gop;
	enc_chn->inFrmRate.frmRateNum = 0;
	enc_chn->inFrmRate.frmRateDen = 0;
	enc_chn->chnFpsMask = 0;
	enc_chn->fpsMaskSize = 0;
	enc_chn->encodingFrameCnt = 0;
	enc_chn->endencodeFrameCnt = 0;
	enc_chn->endrelaseFrameCnt = 0;

	if (pthread_create(&enc_chn->i264e.StrmTid, NULL, update_frmstrm, enc_chn) < 0) {
		IMP_LOG_ERR(TAG, "pthread_create update_frmstrm failed\n");
		return -1;
	}

	if (IS_SOC_SERIES(T20)) {
		int ret = channel_ncu_data_init(enc_chn);
		if (ret < 0) {
			IMP_LOG_WARN(TAG, "Channel-%d ncu off\n", enc_chn->index);
		}
	}

	return 0;
}

static int channel_i264e_encoder_exit(EncChannel *enc_chn)
{
	pthread_cancel(enc_chn->i264e.StrmTid);
	pthread_join(enc_chn->i264e.StrmTid, NULL);

	if (enc_chn->i264e.i264eHandler != NULL) {
		i264e_deinit(enc_chn->i264e.i264eHandler);
		enc_chn->i264e.i264eHandler = NULL;
	}

	if (enc_chn->i264e.userDataConstraints != NULL) {
		imp_video_container_deinit(enc_chn->i264e.userDataConstraints);
		enc_chn->i264e.userDataConstraints = NULL;
	}

	if (IS_SOC_SERIES(T20)) {
		int ret = channel_ncu_data_exit(enc_chn);
		if (ret < 0) {
			IMP_LOG_WARN(TAG, "Channel-%d ncu off\n", enc_chn->index);
		}
	}

	return 0;
}

static int channel_jpege_encoder_init(EncChannel *enc_chn)
{
	ijpege_param_t ijpege_param;
	ijpege_t *ijpege_handler;

	ijpege_param_default(&ijpege_param);
#ifdef CONFIG_SOC_M200
	ijpege_param.soc = C_M200;
#else
	if (IS_SOC_SERIES(T10)) {
		ijpege_param.soc = C_T10;
	} else if (IS_SOC_SERIES(T20)) {
		ijpege_param.soc = C_T20;
	} else if(IS_SOC_SERIES(T30)) {
		ijpege_param.soc = C_T30;
	}else if(IS_SOC_SERIES(T21)) {
		ijpege_param.soc = C_T21;
	}else if(IS_SOC_SERIES(T23)) {
		ijpege_param.soc = C_T23;
	}else {
		IMP_LOG_ERR(TAG, "soc type (%d) not support yet\n", get_cpu_id());
		return -1;
	}
#endif

	if((true == enc_chn->attr.bEnableIvdc) && (enc_chn->direct_mode)) {
		ijpege_param.i_width = C_ALIGN(enc_chn->attr.encAttr.picWidth, 16);
		ijpege_param.i_height = enc_chn->attr.encAttr.picHeight;
	} else {
		ijpege_param.i_width = enc_chn->attr.encAttr.picWidth;
		ijpege_param.i_height = enc_chn->attr.encAttr.picHeight;
	}

	ijpege_param.index = enc_chn->index;
	ijpege_param.ckmalloc = video_vbm_malloc;
	ijpege_param.ckfree = video_vbm_free;
	ijpege_param.ckvirt_to_phys = video_vbm_virt_to_phys;
	ijpege_param.ckphys_to_virt = video_vbm_phys_to_virt;
	ijpege_param.b_tlb = 0;
	ijpege_param.b_use_phy = 1;
	ijpege_param.i_csp = C_CSP_NV12; /* NV12 only */
	ijpege_param.b_user_nalbuffer = 1;

	ijpege_handler = ijpege_init(&ijpege_param);

	if (ijpege_handler == NULL) {
		IMP_LOG_ERR(TAG, "JPEG Encoder open failed\n");
		return -1;
	}

	ijpege_pic_t pic_in;
	memset(&pic_in, 0, sizeof(ijpege_pic_t));
	pic_in.img.i_csp = ijpege_param.i_csp;
	pic_in.i_ql = enc_chn->attr.encAttr.profile;
	pic_in.i_pic_struct = C_PIC_STRUCT_AUTO;
	pic_in.img.i_plane = 2;

	pic_in.img.i_stride[0] = pic_in.img.i_stride[1] = C_ALIGN(ijpege_param.i_width, 16);
	pic_in.img.i_lines[0] = C_ALIGN(ijpege_param.i_height, 16);
	pic_in.img.i_lines[1] = C_ALIGN(ijpege_param.i_height, 16) / 2;

	enc_chn->jpege.ijpegeHandler = ijpege_handler;
	enc_chn->jpege.ijpegeParam = ijpege_param;
	enc_chn->jpege.cPicIn = pic_in;

	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->encodingFrameCnt = 0;
	enc_chn->endencodeFrameCnt = 0;
	enc_chn->endrelaseFrameCnt = 0;
	pthread_mutex_unlock(&enc_chn->mutex);

	return 0;
}

static int channel_jpege_encoder_exit(EncChannel *enc_chn)
{
	if (!enc_chn || enc_chn->jpege.ijpegeHandler == NULL)
		return 0;

	ijpege_deinit(enc_chn->jpege.ijpegeHandler);
	enc_chn->jpege.ijpegeHandler = NULL;

	return 0;
}

static int channel_i265e_encoder_init(EncChannel *enc_chn)
{
#ifdef CONFIG_SOC_T30
	IMPEncoderCHNAttr *chn_attr = &enc_chn->attr;
	i265e_t *i265e_handler;
	i265e_param_t i265e_param;

	i265e_param_default(&i265e_param);

	if (IS_SOC_SERIES(T30)){
		i265e_param.socType = C_T30;
    } else {
		IMP_LOG_ERR(TAG, "soc type (%d) not support yet\n", get_cpu_id());
		return -1;
    }

    i265e_param.bUserNalbuf = 1;
    i265e_param.bWaterMark = !!enc_chn->b_fisheye;
    i265e_param.taskNum = 1;
    i265e_param.threadNum = 1;

    /* should to be confirmed */
	i265e_param.sourceMaxWidth = i265e_param.sourceWidth = chn_attr->encAttr.picWidth;
	i265e_param.sourceMaxHeight = i265e_param.sourceHeight = chn_attr->encAttr.picHeight;

	i265e_param.ckMalloc = video_vbm_malloc;
	i265e_param.ckFree = video_vbm_free;
	i265e_param.ckVirt2Phys = video_vbm_virt_to_phys;
	i265e_param.ckPhys2Virt = video_vbm_phys_to_virt;

	i265e_param.internalCsp = C_CSP_NV12; /* Fixed input format */

	if (chn_attr->encAttr.userData.maxUserDataCnt > 0) {
		chn_attr->encAttr.userData.maxUserDataCnt = c_clip3(chn_attr->encAttr.userData.maxUserDataCnt, 0, NR_MAX_ENC_CHN_USERDATACNT);
		chn_attr->encAttr.userData.maxUserDataSize = c_clip3(chn_attr->encAttr.userData.maxUserDataSize, 16, NR_MAX_ENC_CHN_USERDATASIZE);
		enc_chn->i265e.userDataConstraints = imp_video_container_init(chn_attr->encAttr.userData.maxUserDataCnt, chn_attr->encAttr.userData.maxUserDataSize + 20);
		if (enc_chn->i265e.userDataConstraints == NULL) {
			IMP_LOG_DBG(TAG, "%s(%d):imp_video_container_init failed\n", __func__, __LINE__);
			return -1;
		}
	}

	switch (chn_attr->rcAttr.attrRcMode.rcMode) {
	case ENC_RC_MODE_FIXQP:
		i265e_param.rc.rateControlMode = I265E_RC_CQP;
		i265e_param.rc.qp = chn_attr->rcAttr.attrRcMode.attrH265FixQp.qp;
		break;
	case ENC_RC_MODE_CBR:
		i265e_param.rc.rateControlMode = I265E_RC_CBR;
		i265e_param.rc.qpMax = chn_attr->rcAttr.attrRcMode.attrH265Cbr.maxQp;
		i265e_param.rc.qpMin = chn_attr->rcAttr.attrRcMode.attrH265Cbr.minQp;
		i265e_param.rc.staticTime = chn_attr->rcAttr.attrRcMode.attrH265Cbr.staticTime;
		i265e_param.rc.bitrate = chn_attr->rcAttr.attrRcMode.attrH265Cbr.outBitRate;
		i265e_param.rc.ibias = chn_attr->rcAttr.attrRcMode.attrH265Cbr.iBiasLvl;
        i265e_param.rc.qpStep = chn_attr->rcAttr.attrRcMode.attrH265Cbr.frmQPStep;
		i265e_param.rc.gopStep = chn_attr->rcAttr.attrRcMode.attrH265Cbr.gopQPStep;
		i265e_param.rc.flucLvl = chn_attr->rcAttr.attrRcMode.attrH265Cbr.flucLvl;
		break;
	case ENC_RC_MODE_VBR:
		i265e_param.rc.rateControlMode = I265E_RC_VBR;
		i265e_param.rc.qpMax = chn_attr->rcAttr.attrRcMode.attrH265Vbr.maxQp;
		i265e_param.rc.qpMin = chn_attr->rcAttr.attrRcMode.attrH265Vbr.minQp;
		i265e_param.rc.staticTime = chn_attr->rcAttr.attrRcMode.attrH265Vbr.staticTime;
		i265e_param.rc.bitrate = chn_attr->rcAttr.attrRcMode.attrH265Vbr.maxBitRate;
		i265e_param.rc.ibias = chn_attr->rcAttr.attrRcMode.attrH265Vbr.iBiasLvl;
		i265e_param.rc.changePos = chn_attr->rcAttr.attrRcMode.attrH265Vbr.changePos;
		i265e_param.rc.qualityLvl = chn_attr->rcAttr.attrRcMode.attrH265Vbr.qualityLvl;
        i265e_param.rc.qpStep = chn_attr->rcAttr.attrRcMode.attrH265Vbr.frmQPStep;
		i265e_param.rc.gopStep = chn_attr->rcAttr.attrRcMode.attrH265Vbr.gopQPStep;
		i265e_param.rc.flucLvl = chn_attr->rcAttr.attrRcMode.attrH265Vbr.flucLvl;
		break;
	case ENC_RC_MODE_SMART:
		i265e_param.rc.rateControlMode = I265E_RC_SMART;
		i265e_param.rc.qpMax = chn_attr->rcAttr.attrRcMode.attrH265Smart.maxQp;
		i265e_param.rc.qpMin = chn_attr->rcAttr.attrRcMode.attrH265Smart.minQp;
		i265e_param.rc.staticTime = chn_attr->rcAttr.attrRcMode.attrH265Smart.staticTime;
		i265e_param.rc.bitrate = chn_attr->rcAttr.attrRcMode.attrH265Smart.maxBitRate;
		i265e_param.rc.ibias = chn_attr->rcAttr.attrRcMode.attrH265Smart.iBiasLvl;
		i265e_param.rc.changePos = chn_attr->rcAttr.attrRcMode.attrH265Smart.changePos;
		i265e_param.rc.qualityLvl = chn_attr->rcAttr.attrRcMode.attrH265Smart.qualityLvl;
        i265e_param.rc.qpStep = chn_attr->rcAttr.attrRcMode.attrH265Smart.frmQPStep;
		i265e_param.rc.gopStep = chn_attr->rcAttr.attrRcMode.attrH265Smart.gopQPStep;
		i265e_param.rc.flucLvl = chn_attr->rcAttr.attrRcMode.attrH265Smart.flucLvl;
		break;
	default:
		IMP_LOG_ERR(TAG, "H265 RC Mode %d not support yet\n", chn_attr->rcAttr.attrRcMode.rcMode);
		return -1;
	}

	i265e_param.gopSize = chn_attr->rcAttr.maxGop;
	c_reduce_fraction(&chn_attr->rcAttr.outFrmRate.frmRateNum, &chn_attr->rcAttr.outFrmRate.frmRateDen);
	i265e_param.outFpsNum = chn_attr->rcAttr.outFrmRate.frmRateNum;
	i265e_param.outFpsDen = chn_attr->rcAttr.outFrmRate.frmRateDen;
	if (i265e_param.outFpsNum == 0 || i265e_param.outFpsDen == 0) {
		i265e_param.outFpsNum = chn_attr->rcAttr.outFrmRate.frmRateNum = 25;
		i265e_param.outFpsDen = chn_attr->rcAttr.outFrmRate.frmRateDen = 1;
	}
    if ((i265e_param.gopSize * i265e_param.outFpsDen) % i265e_param.outFpsNum) {
        i265e_param.gopSize = (i265e_param.gopSize / i265e_param.outFpsNum + 1) * i265e_param.outFpsNum;
    }
    chn_attr->rcAttr.maxGop = i265e_param.gopSize;

	i265e_param.hskip.i_skip_type = chn_attr->rcAttr.attrHSkip.hSkipAttr.skipType;
	i265e_param.hskip.m = chn_attr->rcAttr.attrHSkip.hSkipAttr.m;
	i265e_param.hskip.n = chn_attr->rcAttr.attrHSkip.hSkipAttr.n;
	i265e_param.hskip.max_same_scenecnt = chn_attr->rcAttr.attrHSkip.hSkipAttr.maxSameSceneCnt;
	i265e_param.hskip.b_enable_scenecut = chn_attr->rcAttr.attrHSkip.hSkipAttr.bEnableScenecut;
	i265e_param.hskip.b_black_enhance = chn_attr->rcAttr.attrHSkip.hSkipAttr.bBlackEnhance;
	if ((chn_attr->rcAttr.attrHSkip.hSkipAttr.skipType >= IMP_Encoder_STYPE_N4X)
			|| (chn_attr->rcAttr.attrHSkip.maxHSkipType >= IMP_Encoder_STYPE_N4X)) {
		i265e_param.maxHSkipType = chn_attr->rcAttr.attrHSkip.maxHSkipType = IMP_Encoder_STYPE_H1M_TRUE;
	} else {
		i265e_param.maxHSkipType = chn_attr->rcAttr.attrHSkip.maxHSkipType = IMP_Encoder_STYPE_N2X;
	}

	i265e_param.superFrm.iframe_bits_thresd = (chn_attr->encAttr.bufSize - 8192 - 64 * 2) * 8;

	if (access("/tmp/encattr", F_OK) == 0) {
		dump_encoder_chn_attr(enc_chn->index, chn_attr, __func__, __LINE__);
	}

	i265e_handler = i265e_init(&i265e_param);
	if (i265e_handler == NULL) {
		IMP_LOG_ERR(TAG, "Encoder open error\n");
		return -1;
	}

	i265e_pic_t *i265e_pic = &enc_chn->i265e.xPicIn;
	memset(i265e_pic, 0, sizeof(i265e_pic_t));

	/* Init i265e picture */
	i265e_pic->img.i_csp = i265e_param.internalCsp;
	i265e_pic->img.i_plane = 2;
	i265e_pic->img.i_stride[0] = i265e_pic->img.i_stride[1] = C_ALIGN(i265e_param.sourceMaxWidth, 16);
	i265e_pic->img.i_lines[0] = C_ALIGN(i265e_param.sourceMaxHeight, 16);
	i265e_pic->img.i_lines[1] = C_ALIGN(i265e_param.sourceMaxHeight, 16) / 2;
	i265e_pic->img.is_vir = 0;

	enc_chn->i265e.i265eHandler = i265e_handler;
	enc_chn->i265e.i265eParam = i265e_param;
	enc_chn->i265e.pts = 0;

	enc_chn->i265e.usedStat.used_count = 0;
	enc_chn->i265e.usedStat.used_frame = NULL;

	enc_chn->i265e.created_align_skip_type = i265e_param.maxHSkipType;

	enc_chn->setFrmRate.frmRateNum = i265e_param.outFpsNum;
	enc_chn->setFrmRate.frmRateDen = i265e_param.outFpsDen;
	enc_chn->setMaxGop = i265e_param.gopSize;
	enc_chn->inFrmRate.frmRateNum = 0;
	enc_chn->inFrmRate.frmRateDen = 0;
	enc_chn->chnFpsMask = 0;

	if (pthread_create(&enc_chn->i265e.StrmTid, NULL, update_frmstrm, enc_chn) < 0) {
		IMP_LOG_ERR(TAG, "pthread_create update_frmstrm failed\n");
		return -1;
	}

	return 0;
#endif
}

static int channel_i265e_encoder_exit(EncChannel *enc_chn)
{
#ifdef CONFIG_SOC_T30
	pthread_cancel(enc_chn->i265e.StrmTid);
	pthread_join(enc_chn->i265e.StrmTid, NULL);

	if (enc_chn->i265e.i265eHandler != NULL) {
		i265e_deinit(enc_chn->i265e.i265eHandler);
		enc_chn->i265e.i265eHandler = NULL;
	}

	if (enc_chn->i265e.userDataConstraints != NULL) {
		imp_video_container_deinit(enc_chn->i265e.userDataConstraints);
		enc_chn->i265e.userDataConstraints = NULL;
	}

	return 0;
#endif
}

static int channel_encoder_init(EncChannel *enc_chn)
{
	int ret = -1;

	switch (enc_chn->attr.encAttr.enType) {
	case PT_H264:
		ret = channel_i264e_encoder_init(enc_chn);
		break;
	case PT_JPEG:
		ret = channel_jpege_encoder_init(enc_chn);
		break;
	case PT_H265:
		ret = channel_i265e_encoder_init(enc_chn);
		break;
	default:
		IMP_LOG_ERR(TAG, "Channel init: Unknow payload type %d\n",
					enc_chn->attr.encAttr.enType);
		break;
	}

	return ret;
}

static int channel_encoder_exit(EncChannel *enc_chn)
{
	int ret = -1;

	switch (enc_chn->attr.encAttr.enType) {
	case PT_H264:
		ret = channel_i264e_encoder_exit(enc_chn);
		break;
	case PT_JPEG:
		ret = channel_jpege_encoder_exit(enc_chn);
		break;
	case PT_H265:
		ret = channel_i265e_encoder_exit(enc_chn);
		break;
	default:
		IMP_LOG_ERR(TAG, "Channel exit: Unknow payload type %d\n",
					enc_chn->attr.encAttr.enType);
		break;
	}

	return ret;
}

static float channel_get_encode_ratio(IMPPayloadType enType, uint32_t picWidth, uint32_t picHeight, int b_enable_bufshare)
{
	float ratio = 1.0;

	switch(enType) {
		case PT_JPEG:
			ratio = 2.0;
			break;
		case PT_H264:
			if (b_enable_bufshare) {
				if ((picWidth <= 1920) && (picHeight <= 1088)) {
					ratio = 2.0;	// 1555200 + 8192 + 64 * 2 = 1526KB, calc with 1920 * 1080
				} else {
					ratio = 2.5;	// 1887436 + 8192 + 64 * 2 = 1851KB, calc with 2048 * 1536
				}
			} else {
				if ((picWidth <= 800) && (picHeight <= 600)) {
					ratio = 2.0;	// 240000 + 8192 + 64 * 2 = 244224 = 238KB
				} else if ((picWidth <= 1920) && (picHeight <= 1080)) {
					ratio = 3.0;	// 518400 + 8192 + 64 * 2 = 522624 = 510KB
				} else {
					ratio = 3.0;	// 589824 + 8192 + 64 * 2 = 594048 = 580KB, calc with 2048 * 1536
				}
			}
			break;
		case PT_H265:
			if ((picWidth <= 800) && (picHeight <= 600)) {
				ratio = 2.0;	// 180000 + 8192 + 64 * 2 = 184224 = 180KB
			} else if ((picWidth <= 1920) && (picHeight <= 1080)) {
				ratio = 3.0;	// 388800 + 8192 + 64 * 2 = 393024 = 384KB
			} else {
				ratio = 3.0; // 471859 + 8192 + 64 * 2 = 476083 = 465KB
			}
			break;
	}

	return ratio;
}

static int channel_buffer_init(EncChannel *enc_chn)
{
	int size = enc_chn->nr_stream_buffer * sizeof(FrameStream);

	enc_chn->frame_streams = malloc(size);
	if (enc_chn->frame_streams == NULL) {
		IMP_LOG_ERR(TAG, "malloc enc_chn->frame_streams enc_chn->index=%d, failed\n", enc_chn->index);
		return -1;
	}
	memset(enc_chn->frame_streams, 0, size);

	uint32_t buffer_size_total = enc_chn->attr.encAttr.bufSize
		* enc_chn->nr_stream_buffer;

	if (enc_chn->stream_buffer_base
		&& (buffer_size_total > enc_chn->stream_buffer_size)) {
		IMP_LOG_DBG(TAG, "channel-%d buffer=%d need=%d \n", enc_chn->index, enc_chn->stream_buffer_size, buffer_size_total);
		free(enc_chn->stream_buffer_base);
		enc_chn->stream_buffer_base = NULL;
	}

	if (enc_chn->stream_buffer_base == NULL) {
		void *buffer_addr_base;
		buffer_addr_base = malloc(buffer_size_total);
		if (buffer_addr_base == NULL) {
			IMP_LOG_ERR(TAG, "Channel buffer alloc failed(%s)\n", strerror(errno));
			return -1;
		}
		enc_chn->stream_buffer_base = buffer_addr_base;
		enc_chn->stream_buffer_size = buffer_size_total;
		IMP_LOG_DBG(TAG, "channel-%d bufSize(%d) x nr_stream_buffer(%d) = buffer malloc size=%d addr=%p\n", enc_chn->index, enc_chn->attr.encAttr.bufSize, enc_chn->nr_stream_buffer, enc_chn->stream_buffer_size, buffer_addr_base);
	} else {
		IMP_LOG_DBG(TAG, "channel-%d used previous stream buffer\n", enc_chn->index);
	}

	int i;
	for (i = 0; i < enc_chn->nr_stream_buffer; i++) {
		int step = (int)enc_chn->attr.encAttr.bufSize;
		enc_chn->frame_streams[i].stream_buffer =
			(void *)((int)enc_chn->stream_buffer_base
					 + (i * step));
	}

	Fifo_Init(&enc_chn->wr_frameStreamFifo, enc_chn->nr_stream_buffer);
	for (i = 0; i < enc_chn->nr_stream_buffer; i++) {
		Fifo_Queue(&enc_chn->wr_frameStreamFifo, &enc_chn->frame_streams[i], AL_WAIT_FOREVER);
	}
	Fifo_Init(&enc_chn->rd_frameStreamFifo, enc_chn->nr_stream_buffer);

	return 0;
}

static int channel_buffer_exit(EncChannel *enc_chn)
{
#if 1
	if (enc_chn->stream_buffer_base)
		free(enc_chn->stream_buffer_base);
	enc_chn->stream_buffer_base = NULL;
#endif
	Fifo_Deinit(&enc_chn->rd_frameStreamFifo);
	Fifo_Deinit(&enc_chn->wr_frameStreamFifo);
	if (enc_chn->frame_streams) {
		free(enc_chn->frame_streams);
		enc_chn->frame_streams = NULL;
	}

	return 0;
}

static encoder_max_width = 0;
static encoder_max_height = 0;

_get_encoder_max_resolution(int *width, int *height)
{
    *width = encoder_max_width;
    *height = encoder_max_height;
}

int IMP_Encoder_CreateChn(int encChn, const IMPEncoderCHNAttr *attr)
{
    int ret;
	IMPCPUID cpu_id;
	int sensor_width = 0;
	int sensor_height = 0;
	int direct_mode = 0;
	int ivdc_mem_line = 0;
	int ivdc_fd = -1;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	if (attr == NULL) {
		IMP_LOG_ERR(TAG, "Channel Attr is NULL\n");
		return -1;
	}

    EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index >= 0) {
		IMP_LOG_ERR(TAG, "This channel has already been created\n");
		return -1;
	}
    get_sensor_resolution(&sensor_width, &sensor_height);
    cpu_id = get_cpu_id();
	if (cpu_id == SOC_T21_L) {
		if ((sensor_width <= 1280)&&(sensor_height <= 960)) {
			;
		} else {
			if ((attr->encAttr.picWidth > 1280)||(attr->encAttr.picHeight > 960)) {
				IMP_LOG_ERR(TAG, "Error: width/height is too large!!!! frame->width = %d, frame->height = %d\n",
					attr->encAttr.picWidth, attr->encAttr.picHeight);
				return -1;
			}
		}
	}
	if (attr->encAttr.picWidth > encoder_max_width)
		encoder_max_width = attr->encAttr.picWidth;
	if (attr->encAttr.picHeight > encoder_max_height)
		encoder_max_height = attr->encAttr.picHeight;

    /*
    IMP_LOG_INFO(TAG, "%s,%d: sensor_width = %d, sensor_height = %d, encoder_widht = %d, encoder_height = %d\n",
		 __func__, __LINE__, sensor_width, sensor_height, encoder_max_width, encoder_max_height);
    */
	if (access("/tmp/encattr", F_OK) == 0) {
		dump_encoder_chn_attr(encChn, attr, __func__, __LINE__);
	}

    int nr_stream_buffer_bak = enc_chn->nr_stream_buffer;
    int b_fisheye_bak = enc_chn->b_fisheye;
    void *stream_buffer_bak = enc_chn->stream_buffer_base;
    int stream_buffer_size_bak = enc_chn->stream_buffer_size;
	int b_enable_bufshare_bak = enc_chn->b_enable_bufshare;

	if ((enc_chn->attr.encAttr.enType == PT_H264) && enc_chn->padData.padEnable) {
		PadFrameAttr padAttr;
		memcpy(&padAttr, &enc_chn->padData.padAttr, sizeof(PadFrameAttr));
		memset(enc_chn, 0, sizeof(EncChannel));
		enc_chn->padData.padEnable = 1;
		memcpy(&enc_chn->padData.padAttr, &padAttr, sizeof(PadFrameAttr));
	} else {
		memset(enc_chn, 0, sizeof(EncChannel));
	}
    enc_chn->b_fisheye = b_fisheye_bak;
    enc_chn->nr_stream_buffer = nr_stream_buffer_bak;
    enc_chn->stream_buffer_base = stream_buffer_bak;
    enc_chn->stream_buffer_size = stream_buffer_size_bak;
	//enc_chn->b_enable_bufshare = b_enable_bufshare_bak;
	enc_chn->b_enable_bufshare = 1;

    enc_chn->index = encChn;
    enc_chn->stat.work_done = 1;
    enc_chn->recv_pic = 0;
    enc_chn->idr_request = 1;

    memcpy(&enc_chn->attr, attr, sizeof(IMPEncoderCHNAttr));

    //IMP_LOG_DBG(TAG, "encChn=%d,picWidth=%d,picHeight=%d,enable=%d,x=%u,y=%u, w=%u, h = %u\n", encChn,
    //enc_chn->attr.encAttr.picWidth, enc_chn->attr.encAttr.picHeight,
    //enc_chn->attr.encAttr.crop.enable, enc_chn->attr.encAttr.crop.x, enc_chn->attr.encAttr.crop.y,
    //enc_chn->attr.encAttr.crop.w, enc_chn->attr.encAttr.crop.h);

	if (true == attr->bEnableIvdc) {
		ivdc_fd = open("/dev/misc-ivdc", O_RDONLY);
		if (ivdc_fd < 0) {
			IMP_LOG_ERR(TAG,"open misc-ivdc failed\n");
			return -1;
		}

		ret = ioctl(ivdc_fd, TISP_VIDIOC_GET_DIRECT, &direct_mode);
		if (ret < 0) {
			IMP_LOG_ERR(TAG, "%s(%d): TISP_VIDIOC_GET_DIRECT failed\n", __func__, __LINE__);
			return -1;
		}
		ret = ioctl(ivdc_fd, TISP_VIDIOC_MEM_LINE, &ivdc_mem_line);
		if (ret < 0) {
			IMP_LOG_ERR(TAG, "%s(%d): TISP_VIDIOC_MEM_LINE failed\n", __func__, __LINE__);
			return -1;
		}

		if (direct_mode) {
			enc_chn->ivdc_fd = ivdc_fd;
			enc_chn->direct_mode = direct_mode;
			enc_chn->ivdc_mem_line = ivdc_mem_line;
		}
	}

	if (((1 == enc_chn->direct_mode) || (2 == enc_chn->direct_mode) || (3 == enc_chn->direct_mode)) && (0 == enc_chn->index)) {
		g_direct_mode = enc_chn->direct_mode;
	}

	if((enc_chn->attr.encAttr.enType == PT_H264) && enc_chn->padData.padEnable) {
		sem_init(&enc_chn->padData.padFreeHandlerSem, 0, enc_chn->padData.padAttr.nrKeepPadFrame);
		sem_init(&enc_chn->padData.padBusyHandlerSem, 0, 0);
		sem_init(&enc_chn->padData.padDoneHandlerSem, 0, 0);
		enc_chn->padData.padConstraints = imp_video_container_init(enc_chn->padData.padAttr.nrKeepPadFrame, sizeof(PadStreamHandler));
		if (enc_chn->padData.padConstraints == NULL) {
			enc_chn->index = -1;
			IMP_LOG_ERR(TAG, "%s(%d):imp_video_container_init(%d,%d) failed\n", __func__, __LINE__, enc_chn->padData.padAttr.nrKeepPadFrame, sizeof(PadStreamHandler));
			return -1;
		}
		int tlb_size = 4096 + 4096 * 10;
		char tlb_owner[32];
		sprintf(tlb_owner, "vputlb%d", encChn);
		ret = IMP_Alloc(&enc_chn->padData.padTlb, tlb_size, tlb_owner);
		if(ret != 0) {
			enc_chn->index = -1;
			IMP_LOG_ERR(TAG, "IMP alloc pad tlb buffer failed\n");
			return -1;
		}
		enc_chn->padData.padTimeSpec.tv_sec = enc_chn->padData.padAttr.padTimeoutMsec / 1000;
		enc_chn->padData.padTimeSpec.tv_nsec = (enc_chn->padData.padAttr.padTimeoutMsec % 1000) * 1000000;
		enc_chn->padData.padState = PAD_SYNC_NONE;
		enc_chn->attr.encAttr.picHeight *= 2;
	}

	if (enc_chn->nr_stream_buffer <= 0) {
		if (enc_chn->attr.encAttr.enType == PT_JPEG)
			enc_chn->nr_stream_buffer = 1;
		else
			enc_chn->nr_stream_buffer = NR_MAX_ENC_CHN_STREAM;
	}

	float ratio = channel_get_encode_ratio(enc_chn->attr.encAttr.enType, enc_chn->attr.encAttr.picWidth,
			enc_chn->attr.encAttr.picHeight, enc_chn->b_enable_bufshare);
    if ((enc_chn->attr.encAttr.bufSize <= 0) || enc_chn->b_enable_bufshare) {
		enc_chn->attr.encAttr.bufSize = 1.0 * enc_chn->attr.encAttr.picWidth
			* enc_chn->attr.encAttr.picHeight * 3 / 2 / ratio + 8192 + 64 * 2;
		enc_chn->attr.encAttr.bufSize = C_ALIGN(enc_chn->attr.encAttr.bufSize, 4);
    } else if (enc_chn->attr.encAttr.enType != PT_JPEG) {
		int minBufSize = 1.0 * enc_chn->attr.encAttr.picWidth * enc_chn->attr.encAttr.picHeight * 3 / 2 / ratio / 2 + 8192 + 64 * 2;
		if (minBufSize < (8192 + 64 * 2) * 2) {
			minBufSize = (8192 + 64 * 2) * 2;
		}
		if (enc_chn->attr.encAttr.bufSize < minBufSize) {
			IMP_LOG_WARN(TAG, "encChn=%d, force enc_chn->attr.encAttr.bufSize(%d) to minBufSize(%d)\n", encChn, enc_chn->attr.encAttr.bufSize, minBufSize);
			enc_chn->attr.encAttr.bufSize = minBufSize;
		}
    }

    sem_init(&enc_chn->rd_sem, 0, 0);
    sem_init(&enc_chn->wr_sem, 0, enc_chn->nr_stream_buffer);
	ret = pthread_mutex_init(&enc_chn->mutex, NULL);
	if (ret < 0) {
		enc_chn->index = -1;
		IMP_LOG_ERR(TAG, "pthread_mutex_init failed\n");
		return -1;
	}

	ret = sem_init(&enc_chn->poll_sem, 0, 0);
	if (ret < 0) {
		enc_chn->index = -1;
		IMP_LOG_ERR(TAG, "sem_init(&enc_chn->poll_sem) failed\n");
		return -1;
	}

	ret = channel_buffer_init(enc_chn);
	if (ret < 0) {
		enc_chn->index = -1;
		IMP_LOG_ERR(TAG, "Channel%d stream buffer init failed\n", encChn);
		return ret;
	}

	ret = channel_encoder_init(enc_chn);
	if (ret < 0) {
		IMP_LOG_ERR(TAG, "Channel%d encoder init failed\n", encChn);
		channel_buffer_exit(enc_chn);
		enc_chn->index = -1;
		return ret;
	}

	pthread_mutex_init(&enc_chn->efd_mutex, NULL);
	pthread_cond_init(&enc_chn->efd_cond, NULL);
	enc_chn->efd = eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE);
	if (enc_chn->efd < 0) {
		IMP_LOG_ERR(TAG, "Channel%d create device file handler failed\n", encChn);
		channel_encoder_exit(enc_chn);
		channel_buffer_exit(enc_chn);
		enc_chn->index = -1;
		return ret;
	}
	enc_chn->event_cnt = 0;
	IMP_LOG_DBG(TAG, "enc_chn->index=%d, enc_chn->direct_mode = %d, enc_chn->bEnableIvdc = %d, g_direct_mode = %d\n",
			enc_chn->index, enc_chn->direct_mode, enc_chn->attr.bEnableIvdc, g_direct_mode);

	return 0;
}

int IMP_Encoder_DestroyChn(int encChn)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}
	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (1 == enc_chn->recv_pic) {
		IMP_Encoder_StopRecvPic(encChn);
	}

	if (true == enc_chn->stat.registered) {
		IMP_Encoder_UnRegisterChn(encChn);
	}

	channel_encoder_exit(enc_chn);
	channel_buffer_exit(enc_chn);


	if(enc_chn->padData.padEnable) {
		enc_chn->padData.padEnable = 0;
		enc_chn->padData.padState = PAD_SYNC_NONE;
		IMP_Free(&enc_chn->padData.padTlb, (void *)enc_chn->padData.padTlb.info.vaddr);
		if (enc_chn->padData.padConstraints) {
			imp_video_container_deinit(enc_chn->padData.padConstraints);
		}
		sem_destroy(&enc_chn->padData.padFreeHandlerSem);
		sem_destroy(&enc_chn->padData.padBusyHandlerSem);
		sem_destroy(&enc_chn->padData.padDoneHandlerSem);
	}

	if (enc_chn->resize_frame) {
		free(enc_chn->resize_frame);
		enc_chn->resize_frame = NULL;
	}

	if (enc_chn->resize_tmp_buf) {
		free(enc_chn->resize_tmp_buf);
		enc_chn->resize_tmp_buf = NULL;
	}
	if ((enc_chn->resize_buf)&&(!enc_chn->resize_AtoA)) {
		video_vbm_free(enc_chn->index, enc_chn->resize_buf);
	}
	enc_chn->resize_buf = NULL;

	if (((1 == enc_chn->direct_mode) || (2 == enc_chn->direct_mode) || (3 == enc_chn->direct_mode)) && (0 == enc_chn->index)) {
		g_direct_mode = 0;
	}

	if (true == enc_chn->attr.bEnableIvdc) {
		close(enc_chn->ivdc_fd);
		enc_chn->ivdc_fd = -1;
	}

    close(enc_chn->efd);
	pthread_mutex_destroy(&enc_chn->efd_mutex);
	pthread_mutex_destroy(&enc_chn->efd_cond);
	sem_destroy(&enc_chn->rd_sem);
	sem_destroy(&enc_chn->wr_sem);
	sem_destroy(&enc_chn->poll_sem);
	pthread_mutex_destroy(&enc_chn->mutex);

	void *stream_buffer_bak = enc_chn->stream_buffer_base;
	int stream_buffer_size_bak = enc_chn->stream_buffer_size;
	memset(enc_chn, 0, sizeof(EncChannel));
	enc_chn->stream_buffer_base = stream_buffer_bak;
	enc_chn->stream_buffer_size = stream_buffer_size_bak;

	enc_chn->index = -1;

	return 0;
}

int IMP_Encoder_GetChnAttr(int encChn, IMPEncoderCHNAttr * const attr)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

	if (attr == NULL) {
		IMP_LOG_ERR(TAG, "attr is NULL\n");
		return -1;
	}

	memcpy((void *)attr, (void *)&enc_chn->attr, sizeof(IMPEncoderCHNAttr));

	return 0;
}

int IMP_Encoder_RegisterChn(int encGroup, int encChn)
{
	if (encGroup > NR_MAX_ENC_GROUPS - 1) {
		IMP_LOG_ERR(TAG, "Invalid Encoder Group Num: %d\n", encGroup);
		return -1;
	}

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

	if (enc_chn->direct_mode > 0) {
		if (true == enc_chn->attr.bEnableIvdc) {
			if (!(((1 == enc_chn->direct_mode) && (0 == encGroup))
				|| ((2 == enc_chn->direct_mode) && (((0 == encGroup) && ((0 == encChn) || (2 == encChn))) ||
				((1 == encGroup) && ((1 == encChn) || (3 == encChn)))))
				|| ((3 == enc_chn->direct_mode) && (((0 == encGroup) && ((0 == encChn) || (2 == encChn))) ||
				((1 == encGroup) && ((1 == encChn) || (3 == encChn))) || ((2 == encGroup) && ((4 == encChn) || (5 == encChn))))))) {
					IMP_LOG_ERR(TAG, "%s: Please check IVDC Encoder Channel and Encoder Group\n", __func__);
					return -1;
			}
		}
	}

	Encoder *encoder = get_encoder();
	EncGroup *enc_group = &encoder->encGroup[encGroup];

	int i;
	for (i = 0; i < NR_MAX_ENC_CHN_IN_GROUP; i++) {
		if (enc_group->channel[i] == NULL) {
			enc_group->channel[i] = enc_chn;
			break;
		}
	}

	enc_group->nr_enc_chn++;

	enc_chn->enc_group = enc_group;
	enc_chn->stat.registered = true;

	return 0;
}

int IMP_Encoder_UnRegisterChn(int encChn) /* Incompleted */
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		return 0;
	}

	EncGroup *enc_group = enc_chn->enc_group;
	int i;
	for (i = 0; i < NR_MAX_ENC_CHN_IN_GROUP; i++) {
		if (enc_chn == enc_group->channel[i]) {
			enc_group->channel[i] = NULL;
			break;
		}
	}

	enc_group->nr_enc_chn--;
	enc_chn->stat.registered = false;

	return 0;
}

int IMP_Encoder_StartRecvPic(int encChn)
{
	int i;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

	enc_chn->idr_request = 1;
	enc_chn->recv_pic = 1;

	return 0;
}

int IMP_Encoder_StopRecvPic(int encChn)
{
	int sync_left_stream_times = 10;
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

	EncGroup *encgrp = enc_chn->enc_group;
	Encoder *encoder = get_encoder();
	Group *group = encoder->device->groups[encgrp->index];

	enc_chn->recv_pic = 0;

	while(((enc_chn->stat.leftStreamFrames > 0) || (group->module->in_process == 1) || (enc_chn->stat.work_done == 0)) && sync_left_stream_times--) {
		IMPEncoderStream stream;
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
		while ((enc_chn->stat.leftStreamFrames > 0) && IMP_Encoder_PollingStream(encChn, 1000) >= 0) {
			if (IMP_Encoder_GetStream(encChn, &stream, 1) >= 0) {
				IMP_Encoder_ReleaseStream(encChn, &stream);
			}
		}
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
		usleep(10000);
	}

	if (!enc_chn->resize_frame && !enc_chn->resize_tmp_buf && !enc_chn->resize_buf) {
		if (enc_chn->attr.rcAttr.attrFrmUsed.frmUsedMode == ENC_FRM_REUSED) {
			int unlockcnt = enc_chn->i264e.usedStat.used_count;
			for (;unlockcnt > 0; unlockcnt--) {
				VBMUnlockFrameByVaddr(enc_chn->i264e.usedStat.used_frame->virAddr);
				//VBMUnLockFrame(enc_chn->i264e.usedStat.used_frame);
			}
		}
		enc_chn->i264e.usedStat.used_count = 0;
		enc_chn->i264e.usedStat.used_frame = NULL;
	}

	return 0;
}

int IMP_Encoder_Query(int encChn, IMPEncoderCHNStat *stat)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

	*stat = enc_chn->stat;

	return 0;
}

int IMP_Encoder_GetStream(int encChn, IMPEncoderStream *stream, bool blockFlag)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

    uint64_t efd_val = 0;
    pthread_mutex_lock(&enc_chn->efd_mutex);
    while (enc_chn->event_cnt <= 0) {
        pthread_cond_wait(&enc_chn->efd_cond, &enc_chn->efd_mutex);
    }
    read(enc_chn->efd, &efd_val, sizeof(uint64_t));
    if (efd_val > 1) {
        --efd_val;
        write(enc_chn->efd, &efd_val, sizeof(uint64_t));
    }
    enc_chn->event_cnt--;
    pthread_mutex_unlock(&enc_chn->efd_mutex);
#ifdef SHOW_ENCODE_STREAM_TIME
    int b_dbg_encstream = !access("/tmp/encstream", F_OK);
    if (b_dbg_encstream) {
        /* Mark the start time */
        enc_chn->inStat.start_time_raw = system_gettime(RAW);
        enc_chn->inStat.start_time_thread = system_gettime(THREAD);
        enc_chn->inStat.end_time_raw = enc_chn->inStat.end_time_raw > 0 ? enc_chn->inStat.end_time_raw : enc_chn->inStat.start_time_raw;
        enc_chn->inStat.end_time_thread = enc_chn->inStat.end_time_thread > 0 ? enc_chn->inStat.end_time_thread : enc_chn->inStat.start_time_thread;
        /* Show module gop thread time cost */
        IMP_LOG_DBG(TAG, "%s:chnNum=%d:curtime=%lld, efd_val=%llu, gap elapsed:%lluusec, active:%lluusec\n", __func__, encChn,
                enc_chn->inStat.start_time_raw, efd_val,
                enc_chn->inStat.start_time_raw - enc_chn->inStat.end_time_raw,
                enc_chn->inStat.start_time_thread - enc_chn->inStat.end_time_thread);
    }
#endif

	FrameStream *frmstrm;
	frmstrm = get_filled_framestream(enc_chn, blockFlag);
	if (frmstrm == NULL) {
        IMP_LOG_ERR(TAG, "Encoder Channel%d get_filled_framestream failed\n", encChn);
		return -1;
    }

	stream->packCount = frmstrm->pack_count;
	stream->seq = frmstrm->seq;
	stream->pack = frmstrm->pack;
	if (enc_chn->attr.encAttr.enType != PT_JPEG) {
		stream->refType = frmstrm->refType;
	}

#ifdef SAVE_BUF
	{
		int fd = 0;
		int pi = 0, pl = 0;
		if (enc_chn->index == 0) {
			for (pi = 0; pi < stream->packCount; pi++) {
				if ((access(save_name, R_OK | W_OK) == 0) && ((save_open == 1) || (save_open == 0 && stream->packCount > 1))) {
					save_to_file((uint32_t *)stream->pack[pi].virAddr, stream->pack[pi].length);
					if (save_times % 5000 == 0)  {
						IMP_LOG_INFO(TAG, "save_times = %d\n", save_times);
					}
					save_times++;
				} else {
					save_open = 0;
					save_times = 0;
				}
			}
		}
		if (enc_chn->index == 1) {
			for (pi = 0; pi < stream->packCount; pi++) {
				if (access(save_sec_name, R_OK | W_OK) == 0) {
					if ((fd = open(save_sec_name, O_RDWR | O_APPEND, 0777)) > 0) {
						write(fd, (void *)stream->pack[pi].virAddr, stream->pack[pi].length);
					}
				}
			}
		}
	}
#endif

#ifdef SHOW_CHANNEL_BITRATE
	int i, len = 0;
	for (i = 0; i < stream->packCount; i++) {
		len += stream->pack[i].length;
	}
	bitrate[encChn] += len;
	frmcnt[encChn]++;

	if (frmcnt[encChn] == BITRATE_FRAMES_INTERVAL) {
		int64_t now = system_gettime(RAW) / 1000;
		int br = bitrate[encChn] * 8 / ((int)(now - start_time[encChn]) / 1000);
		IMP_LOG_DBG(TAG, "Bitrate: chn-%d=%d\n", encChn, br);
		frmcnt[encChn] = 0;
		bitrate[encChn] = 0;
		start_time[encChn] = now;
	}
#endif

	return 0;
}

int IMP_Encoder_ReleaseStream(int encChn, IMPEncoderStream *stream)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

	FrameStream *frmstrm = encstrm_to_frmstrm(enc_chn, stream);
	if (frmstrm == NULL) {
		IMP_LOG_ERR(TAG, "encstrm_to_frmstrm failed\n");
		return -1;
	}
	release_used_framestream(enc_chn, frmstrm);
	enc_chn->endrelaseFrameCnt++;
#ifdef SHOW_ENCODE_STREAM_TIME
    int b_dbg_encstream = !access("/tmp/encstream", F_OK);
    if (b_dbg_encstream) {
        /* Mark the end time */
        enc_chn->inStat.end_time_raw = system_gettime(RAW);
        enc_chn->inStat.end_time_thread = system_gettime(THREAD);
        /* Show module thread time cost */
        IMP_LOG_DBG(TAG, "%s:chnNum=%d:curtime=%lld, elapsed:%lluusec, active:%lluusec\n", __func__, encChn,
                enc_chn->inStat.end_time_raw,
                enc_chn->inStat.end_time_raw - enc_chn->inStat.start_time_raw,
                enc_chn->inStat.end_time_thread - enc_chn->inStat.start_time_thread);
    }
#endif

	return 0;
}

int IMP_Encoder_PollingStream(int encChn, uint32_t timeoutMsec)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}
	if (enc_chn->stat.registered == false) {
		return -1;
	}

	// return polling_filled_framestream(enc_chn, enc_chn->recv_pic? timeoutMsec: 0);
	return polling_filled_framestream(enc_chn, timeoutMsec);
}

int IMP_Encoder_GetFd(int encChn)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

    return enc_chn->efd;
}

int IMP_Encoder_RequestIDR(int encChn)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

	enc_chn->idr_request = 1;

	return 0;
}

int IMP_Encoder_FlushStream(int encChn)
{
	IMPEncoderCHNStat stat;
	IMPEncoderStream stream;
	int leftStreamFrames = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d hasn't been created\n", encChn);
		return -1;
	}

	if (IMP_Encoder_Query(encChn, &stat) < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d IMP_Encoder_Query failed\n", encChn);
		return -1;
	}

	leftStreamFrames = stat.leftStreamFrames;

	if (IMP_Encoder_RequestIDR(encChn) < 0) {
		IMP_LOG_ERR(TAG, "Encoder Channel%d IMP_Encoder_RequestIDR failed\n", encChn);
		return -1;
	}

	while (leftStreamFrames-- > 0) {
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
		if (IMP_Encoder_PollingStream(encChn, 1000) >= 0) {
			if (IMP_Encoder_GetStream(encChn, &stream, 1) >= 0) {
				IMP_Encoder_ReleaseStream(encChn, &stream);
			}
		}
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	}

	return 0;
}

int IMP_Encoder_SetMaxStreamCnt(int encChn, int nrMaxStream)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index >= 0) {
		IMP_LOG_ERR(TAG, "Max StreamCnt must be set before channel created, encChn=%d\n", encChn);
		return -1;
	}
	enc_chn->nr_stream_buffer = nrMaxStream;

	return 0;
}

int IMP_Encoder_GetMaxStreamCnt(int encChn, int *nrMaxStream)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	*nrMaxStream = enc_chn->nr_stream_buffer;

	return 0;
}

int IMP_Encoder_SetFisheyeEnableStatus(int encChn, int enable)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index >= 0) {
		IMP_LOG_ERR(TAG, "fisheye enabled status must be set before channel created, encChn=%d\n", encChn);
		return -1;
	}
	enc_chn->b_fisheye = !!enable;

	return 0;
}

int IMP_Encoder_GetFisheyeEnableStatus(int encChn, int *enable)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

	*enable = !!enc_chn->b_fisheye;

	return 0;
}

int IMP_Encoder_SetChnColor2Grey(int encChn, const IMPEncoderColor2GreyCfg *pstColor2Grey)
{
	int ret = 0;
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}
	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_c2g_param_t c2g_param = {pstColor2Grey->enable};
            ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_C2G_ID, &c2g_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set c2g param failed, chn num: %d \n", encChn);
                return -1;
            }
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            int bEnableColor2Gray = pstColor2Grey->enable;
            ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_C2G_ID, &bEnableColor2Gray);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e set c2g param failed, chn num: %d \n", encChn);
                return -1;
            }
        }
#endif
	}
	return 0;
}

int IMP_Encoder_GetChnColor2Grey(int encChn, IMPEncoderColor2GreyCfg *pstColor2Grey)
{
	int ret = 0;
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}
	EncChannel *enc_chn = &g_EncChannel[encChn];
    memset(pstColor2Grey, 0, sizeof(IMPEncoderColor2GreyCfg));

	if (enc_chn) {
		if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_c2g_param_t c2g_param;
            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_C2G_ID, &c2g_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set c2g param failed, chn num: %d\n", encChn);
                return -1;
            }
            pstColor2Grey->enable = c2g_param.on;
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            int bEnableColor2Gray = 0;
            ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_C2G_ID, &bEnableColor2Gray);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e set c2g param failed, chn num: %d\n", encChn);
                return -1;
            }
            pstColor2Grey->enable = bEnableColor2Gray;
        }
#endif
	}
	return 0;
}

int IMP_Encoder_SetChnCrop(int encChn, const IMPEncoderCropCfg *pstCropCfg)
{
	int ret = 0;
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}
	if (((pstCropCfg->x%16)!=0)||((pstCropCfg->y%16)!=0)||((pstCropCfg->w%16)!=0)||((pstCropCfg->h%16)!=0)) {
		IMP_LOG_ERR(TAG, "Invalid Param x:%d,y:%d,w:%d,h:%d\n",
				pstCropCfg->x, pstCropCfg->y, pstCropCfg->w, pstCropCfg->h);
		return -1;
	}
	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_cut_param_t cut_param;
            cut_param.on = pstCropCfg->enable;
            cut_param.start_mb_x = pstCropCfg->x/16;
            cut_param.start_mb_y = pstCropCfg->y/16;
            cut_param.mb_width = pstCropCfg->w/16;
            cut_param.mb_height = pstCropCfg->h/16;
            ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_CUT_ID, &cut_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set cut param failed, encChn:%d \n", encChn);
                return -1;
            }
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            i265e_rcfg_crop_param_t crop_param;
            crop_param.left = pstCropCfg->x;
            crop_param.top = pstCropCfg->y;
            crop_param.width = pstCropCfg->w;
            crop_param.height = pstCropCfg->h;
            ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_CUT_ID, &crop_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e set cut param failed, encChn:%d\n", encChn);
                return -1;
            }
        }
#endif
	}
	return 0;
}

int IMP_Encoder_GetChnCrop(int encChn, IMPEncoderCropCfg *pstCropCfg)
{
	int ret = 0;
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}
	EncChannel *enc_chn = &g_EncChannel[encChn];

    memset(pstCropCfg, 0, sizeof(IMPEncoderCropCfg));

	if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_cut_param_t cut_param;
            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_CUT_ID, &cut_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e get cut param failed, encChn:%d \n", encChn);
                return -1;
            }
            pstCropCfg->enable = cut_param.on;
            pstCropCfg->x = cut_param.start_mb_x*16;
            pstCropCfg->y = cut_param.start_mb_y*16;
            pstCropCfg->w = cut_param.mb_width*16;
            pstCropCfg->h = cut_param.mb_height*16;
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            i265e_rcfg_crop_param_t crop_param;
            ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_CUT_ID, &crop_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e get cut param failed, encChn:%d \n", encChn);
                return -1;
            }
            pstCropCfg->x = crop_param.left;
            pstCropCfg->y = crop_param.top;
            pstCropCfg->w = crop_param.width;
            pstCropCfg->h = crop_param.height;
        }
#endif
	}

	return 0;
}

int IMP_Encoder_SetChnAttrRcMode(int encChn, const IMPEncoderAttrRcMode *pstRcModeCfg)
{
	int ret = 0;
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_rc_param_t rc_param;
            memset(&rc_param, 0, sizeof(i264e_rcfg_rc_param_t));
            rc_param.rc_method = pstRcModeCfg->rcMode;

            if (pstRcModeCfg->rcMode == ENC_RC_MODE_FIXQP) {
                rc_param.rc_method = I264E_RC_CQP;
                rc_param.qp = pstRcModeCfg->attrH264FixQp.qp;
            } else if (pstRcModeCfg->rcMode == ENC_RC_MODE_CBR) {
                rc_param.rc_method = I264E_RC_CBR;
                rc_param.min_qp = pstRcModeCfg->attrH264Cbr.minQp;
                rc_param.max_qp = pstRcModeCfg->attrH264Cbr.maxQp;
                rc_param.bitrate = pstRcModeCfg->attrH264Cbr.outBitRate;
                rc_param.biaslvl = pstRcModeCfg->attrH264Cbr.iBiasLvl;
                rc_param.qp_step = pstRcModeCfg->attrH264Cbr.frmQPStep;
                rc_param.gop_qp_step = pstRcModeCfg->attrH264Cbr.gopQPStep;
                rc_param.adaptive_mode = pstRcModeCfg->attrH264Cbr.adaptiveMode;
                rc_param.gop_relation = pstRcModeCfg->attrH264Cbr.gopRelation;
            } else if (pstRcModeCfg->rcMode == ENC_RC_MODE_VBR) {
                rc_param.rc_method = I264E_RC_VBR;
                rc_param.min_qp = pstRcModeCfg->attrH264Vbr.minQp;
                rc_param.max_qp = pstRcModeCfg->attrH264Vbr.maxQp;
                rc_param.static_time = pstRcModeCfg->attrH264Vbr.staticTime;
                rc_param.max_bitrate = pstRcModeCfg->attrH264Vbr.maxBitRate;
                rc_param.biaslvl = pstRcModeCfg->attrH264Vbr.iBiasLvl;
                rc_param.change_pos = pstRcModeCfg->attrH264Vbr.changePos;
                rc_param.quality_level = pstRcModeCfg->attrH264Vbr.qualityLvl;
                rc_param.qp_step = pstRcModeCfg->attrH264Vbr.frmQPStep;
                rc_param.gop_qp_step = pstRcModeCfg->attrH264Vbr.gopQPStep;
                rc_param.gop_relation = pstRcModeCfg->attrH264Vbr.gopRelation;
            } else if (pstRcModeCfg->rcMode == ENC_RC_MODE_SMART) {
                rc_param.rc_method = I264E_RC_SMART;
                rc_param.min_qp = pstRcModeCfg->attrH264Smart.minQp;
                rc_param.max_qp = pstRcModeCfg->attrH264Smart.maxQp;
                rc_param.static_time = pstRcModeCfg->attrH264Smart.staticTime;
                rc_param.max_bitrate = pstRcModeCfg->attrH264Smart.maxBitRate;
                rc_param.biaslvl = pstRcModeCfg->attrH264Smart.iBiasLvl;
                rc_param.change_pos = pstRcModeCfg->attrH264Smart.changePos;
                rc_param.quality_level = pstRcModeCfg->attrH264Smart.qualityLvl;
                rc_param.qp_step = pstRcModeCfg->attrH264Smart.frmQPStep;
                rc_param.gop_qp_step = pstRcModeCfg->attrH264Smart.gopQPStep;
                rc_param.gop_relation = pstRcModeCfg->attrH264Smart.gopRelation;
            } else {
                IMP_LOG_ERR(TAG, "rcMode error only support fixqp and cbr, vbr and smart encchn:%d\n", encChn);
                return -1;
            }
            if (enc_chn) {
                ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_RC_ID, &rc_param);
                if (ret != 0) {
                    IMP_LOG_ERR(TAG, "i264e set rc param failed, encchn:%d\n", encChn);
                    return -1;
                }
            }
            enc_chn->attr.rcAttr.attrRcMode.rcMode = pstRcModeCfg->rcMode;
            memcpy(&enc_chn->attr.rcAttr.attrRcMode, pstRcModeCfg, sizeof(IMPEncoderAttrRcMode));
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            i265e_rcfg_rc_param_t rc_param;
            memset(&rc_param, 0, sizeof(i265e_rcfg_rc_param_t));
            rc_param.rcMethod = pstRcModeCfg->rcMode;

            if (pstRcModeCfg->rcMode == ENC_RC_MODE_FIXQP) {
                rc_param.rcMethod = I265E_RC_CQP;
                rc_param.qp = pstRcModeCfg->attrH265FixQp.qp;
            } else if (pstRcModeCfg->rcMode == ENC_RC_MODE_CBR) {
                rc_param.rcMethod = I265E_RC_CBR;
                rc_param.qpMax = pstRcModeCfg->attrH265Cbr.maxQp;
                rc_param.qpMin = pstRcModeCfg->attrH265Cbr.minQp;
                rc_param.staticTime = pstRcModeCfg->attrH265Cbr.staticTime;
                rc_param.bitrate = pstRcModeCfg->attrH265Cbr.outBitRate;
                rc_param.ibias = pstRcModeCfg->attrH265Cbr.iBiasLvl;
                rc_param.qpStep = pstRcModeCfg->attrH265Cbr.frmQPStep;
                rc_param.gopStep = pstRcModeCfg->attrH265Cbr.gopQPStep;
                rc_param.flucLvl = pstRcModeCfg->attrH265Cbr.flucLvl;
            } else if (pstRcModeCfg->rcMode == ENC_RC_MODE_VBR) {
                rc_param.rcMethod = I265E_RC_VBR;
                rc_param.qpMax = pstRcModeCfg->attrH265Vbr.maxQp;
                rc_param.qpMin = pstRcModeCfg->attrH265Vbr.minQp;
                rc_param.staticTime = pstRcModeCfg->attrH265Vbr.staticTime;
                rc_param.bitrate = pstRcModeCfg->attrH265Vbr.maxBitRate;
                rc_param.ibias = pstRcModeCfg->attrH265Vbr.iBiasLvl;
                rc_param.changePos = pstRcModeCfg->attrH265Vbr.changePos;
                rc_param.qualityLvl = pstRcModeCfg->attrH265Vbr.qualityLvl;
                rc_param.qpStep = pstRcModeCfg->attrH265Vbr.frmQPStep;
                rc_param.gopStep = pstRcModeCfg->attrH265Vbr.gopQPStep;
                rc_param.flucLvl = pstRcModeCfg->attrH265Vbr.flucLvl;
            } else if (pstRcModeCfg->rcMode == ENC_RC_MODE_SMART) {
                rc_param.rcMethod = I265E_RC_SMART;
                rc_param.qpMax = pstRcModeCfg->attrH265Smart.maxQp;
                rc_param.qpMin = pstRcModeCfg->attrH265Smart.minQp;
                rc_param.staticTime = pstRcModeCfg->attrH265Smart.staticTime;
                rc_param.bitrate = pstRcModeCfg->attrH265Smart.maxBitRate;
                rc_param.ibias = pstRcModeCfg->attrH265Smart.iBiasLvl;
                rc_param.changePos = pstRcModeCfg->attrH265Smart.changePos;
                rc_param.qualityLvl = pstRcModeCfg->attrH265Smart.qualityLvl;
                rc_param.qpStep = pstRcModeCfg->attrH265Smart.frmQPStep;
                rc_param.gopStep = pstRcModeCfg->attrH265Smart.gopQPStep;
                rc_param.flucLvl = pstRcModeCfg->attrH265Smart.flucLvl;
            } else {
                IMP_LOG_ERR(TAG, "rcMode error only support fixqp and cbr, vbr and smart encchn:%d\n", encChn);
                return -1;
            }
            if (enc_chn) {
                ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_RC_ID, &rc_param);
                if (ret != 0) {
                    IMP_LOG_ERR(TAG, "i265e set rc param failed, encchn:%d\n", encChn);
                    return -1;
                }
            }
            enc_chn->attr.rcAttr.attrRcMode.rcMode = pstRcModeCfg->rcMode;
        }
#endif
    }

	return 0;
}

int IMP_Encoder_GetChnAttrRcMode(int encChn, IMPEncoderAttrRcMode *pstRcModeCfg)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_rc_param_t rc_param;

            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_RC_ID, &rc_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set rc param failed, encchn:%d\n", encChn);
                return -1;
            }

            pstRcModeCfg->rcMode = rc_param.rc_method;

            if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_FIXQP) {
                pstRcModeCfg->attrH264FixQp.qp = rc_param.qp;
            } else if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_CBR) {
                pstRcModeCfg->attrH264Cbr.outBitRate = rc_param.bitrate;
                pstRcModeCfg->attrH264Cbr.maxQp = rc_param.max_qp;
                pstRcModeCfg->attrH264Cbr.minQp = rc_param.min_qp;
                pstRcModeCfg->attrH264Cbr.iBiasLvl = rc_param.biaslvl;
                pstRcModeCfg->attrH264Cbr.frmQPStep = rc_param.qp_step;
                pstRcModeCfg->attrH264Cbr.gopQPStep = rc_param.gop_qp_step;
                pstRcModeCfg->attrH264Cbr.adaptiveMode = rc_param.adaptive_mode;
                pstRcModeCfg->attrH264Cbr.gopRelation = rc_param.gop_relation;
            } else if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_VBR) {
                pstRcModeCfg->attrH264Vbr.maxQp = rc_param.max_qp;
                pstRcModeCfg->attrH264Vbr.minQp = rc_param.min_qp;
                pstRcModeCfg->attrH264Vbr.staticTime = rc_param.static_time;
                pstRcModeCfg->attrH264Vbr.maxBitRate = rc_param.max_bitrate;
                pstRcModeCfg->attrH264Vbr.iBiasLvl = rc_param.biaslvl;
                pstRcModeCfg->attrH264Vbr.changePos = rc_param.change_pos ;
                pstRcModeCfg->attrH264Vbr.qualityLvl = rc_param.quality_level ;
                pstRcModeCfg->attrH264Vbr.frmQPStep = rc_param.qp_step;
                pstRcModeCfg->attrH264Vbr.gopQPStep = rc_param.gop_qp_step;
                pstRcModeCfg->attrH264Vbr.gopRelation = rc_param.gop_relation;
            } else if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_SMART) {
                pstRcModeCfg->attrH264Smart.maxQp = rc_param.max_qp;
                pstRcModeCfg->attrH264Smart.minQp = rc_param.min_qp;
                pstRcModeCfg->attrH264Smart.staticTime = rc_param.static_time;
                pstRcModeCfg->attrH264Smart.maxBitRate = rc_param.max_bitrate;
                pstRcModeCfg->attrH264Smart.iBiasLvl = rc_param.biaslvl;
                pstRcModeCfg->attrH264Smart.changePos = rc_param.change_pos ;
                pstRcModeCfg->attrH264Smart.qualityLvl = rc_param.quality_level ;
                pstRcModeCfg->attrH264Smart.frmQPStep = rc_param.qp_step;
                pstRcModeCfg->attrH264Smart.gopQPStep = rc_param.gop_qp_step;
                pstRcModeCfg->attrH264Smart.gopRelation = rc_param.gop_relation;
            } else {
                IMP_LOG_ERR(TAG, "rcMode  only support fixqp,cbr,vbr,smart, encchn:%d\n", encChn);
                return -1;
            }
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            i265e_rcfg_rc_param_t rc_param;
            ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_RC_ID, &rc_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e set rc param failed, encchn:%d\n", encChn);
                return -1;
            }

            pstRcModeCfg->rcMode = rc_param.rcMethod;

            if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_FIXQP) {
                pstRcModeCfg->attrH265FixQp.qp = rc_param.qp;
            } else if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_CBR) {
                pstRcModeCfg->attrH265Cbr.maxQp = rc_param.qpMax;
                pstRcModeCfg->attrH265Cbr.minQp = rc_param.qpMin;
                pstRcModeCfg->attrH265Cbr.staticTime = rc_param.staticTime;
                pstRcModeCfg->attrH265Cbr.outBitRate = rc_param.bitrate;
                pstRcModeCfg->attrH265Cbr.iBiasLvl = rc_param.ibias;
                pstRcModeCfg->attrH265Cbr.frmQPStep = rc_param.qpStep;
                pstRcModeCfg->attrH265Cbr.gopQPStep = rc_param.gopStep;
                pstRcModeCfg->attrH265Cbr.flucLvl = rc_param.flucLvl;
            } else if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_VBR) {
                pstRcModeCfg->attrH265Vbr.maxQp = rc_param.qpMax;
                pstRcModeCfg->attrH265Vbr.minQp = rc_param.qpMin;
                pstRcModeCfg->attrH265Vbr.staticTime = rc_param.staticTime;
                pstRcModeCfg->attrH265Vbr.maxBitRate = rc_param.bitrate;
                pstRcModeCfg->attrH265Vbr.iBiasLvl = rc_param.ibias;
                pstRcModeCfg->attrH265Vbr.changePos = rc_param.changePos;
                pstRcModeCfg->attrH265Vbr.qualityLvl = rc_param.qualityLvl;
                pstRcModeCfg->attrH265Vbr.frmQPStep = rc_param.qpStep;
                pstRcModeCfg->attrH265Vbr.gopQPStep = rc_param.gopStep;
                pstRcModeCfg->attrH265Vbr.flucLvl = rc_param.flucLvl;
            } else if (enc_chn->attr.rcAttr.attrRcMode.rcMode == ENC_RC_MODE_SMART) {
                pstRcModeCfg->attrH265Smart.maxQp = rc_param.qpMax;
                pstRcModeCfg->attrH265Smart.minQp = rc_param.qpMin;
                pstRcModeCfg->attrH265Smart.staticTime = rc_param.staticTime;
                pstRcModeCfg->attrH265Smart.maxBitRate = rc_param.bitrate;
                pstRcModeCfg->attrH265Smart.iBiasLvl = rc_param.ibias;
                pstRcModeCfg->attrH265Smart.changePos = rc_param.changePos;
                pstRcModeCfg->attrH265Smart.qualityLvl = rc_param.qualityLvl;
                pstRcModeCfg->attrH265Smart.frmQPStep = rc_param.qpStep;
                pstRcModeCfg->attrH265Smart.gopQPStep = rc_param.gopStep;
                pstRcModeCfg->attrH265Smart.flucLvl = rc_param.flucLvl;
            } else {
                IMP_LOG_ERR(TAG, "rcMode  only support fixqp,cbr,vbr,smart, encchn:%d\n", encChn);
                return -1;
            }
        }
#endif
    }
	return 0;
}

int IMP_Encoder_GetChnEncType(int encChn, IMPPayloadType *payLoadType)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    *payLoadType = enc_chn->attr.encAttr.enType;

    return 0;
}

int IMP_Encoder_SetChnRcTrigLevel(int encChn, float trigLevel, int newMaxQpThr)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_rc_trig_param_t rc_trig_param;
            rc_trig_param.trigger_level = trigLevel;
            rc_trig_param.new_qp_max_thr = newMaxQpThr;
            ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_RC_TRIG_ID, &rc_trig_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set rc trigger param failed, encchn:%d\n", encChn);
                return -1;
            }
        } else if (enc_chn->attr.encAttr.enType == PT_H265) {
            //TODO I265E_RCFG_RC_TRIG_ID, unsupported temporally
        }
	}

	return 0;
}

int IMP_Encoder_SetChnFrmRate(int encChn, const IMPEncoderFrmRate *pstFps)
{
	IMPEncoderFrmRate outFrmRate = *pstFps;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (!pstFps->frmRateNum || !pstFps->frmRateDen) {
		IMP_LOG_ERR(TAG, "Invalid Param fps: pstFps->frmRateNum=%u, pstFps->frmRateDen=%u\n", pstFps->frmRateNum, pstFps->frmRateDen);
		return -1;
	}
	//IMP_LOG_INFO(TAG, "%s(%d):pstFps->frmRateNum=%u, pstFps->frmRateDen=%u\n", __func__, __LINE__, pstFps->frmRateNum, pstFps->frmRateDen);

	EncChannel *enc_chn = &g_EncChannel[encChn];
	c_reduce_fraction(&outFrmRate.frmRateNum, &outFrmRate.frmRateDen);
	pthread_mutex_lock(&enc_chn->mutex);
	enc_chn->setFrmRate = outFrmRate;
	pthread_mutex_unlock(&enc_chn->mutex);

	return 0;
}

int IMP_Encoder_GetChnFrmRate(int encChn, IMPEncoderFrmRate *pstFps)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_fps_param_t fps_param;
            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_FPS_ID, &fps_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e get fps param failed, encchn:%d\n", encChn);
                return -1;
            }
            pstFps->frmRateNum = fps_param.i_fps_num;
            pstFps->frmRateDen = fps_param.i_fps_den;
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            i265e_rcfg_fps_param_t fps_param;
            ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_FPS_ID, &fps_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e get fps param failed, encchn:%d\n", encChn);
                return -1;
            }
            pstFps->frmRateNum = fps_param.fpsNum;
            pstFps->frmRateDen = fps_param.fpsDen;
        }
#endif
	}

	return 0;
}

int IMP_Encoder_SetChnROI(int encChn, const IMPEncoderROICfg *pstVencRoiCfg)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstVencRoiCfg == NULL) {
		IMP_LOG_ERR(TAG, "Invalid Param roicfg\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_roi_param_t roi_param;
            memset(&roi_param, 0, sizeof(i264e_rcfg_roi_param_t));

            roi_param.idx = pstVencRoiCfg->u32Index;
            roi_param.roi.roi_en = pstVencRoiCfg->bEnable;
            roi_param.roi.roi_md = pstVencRoiCfg->bRelatedQp;
            roi_param.roi.roi_qp = pstVencRoiCfg->s32Qp;
            if (pstVencRoiCfg->rect.p0.x < pstVencRoiCfg->rect.p1.x) {
                roi_param.roi.roi_lmbx = pstVencRoiCfg->rect.p0.x / 16;
                roi_param.roi.roi_rmbx = pstVencRoiCfg->rect.p1.x / 16;
            } else {
                roi_param.roi.roi_lmbx = pstVencRoiCfg->rect.p1.x / 16;
                roi_param.roi.roi_rmbx = pstVencRoiCfg->rect.p0.x / 16;
            }

            if (pstVencRoiCfg->rect.p0.y < pstVencRoiCfg->rect.p1.y) {
                roi_param.roi.roi_umby = pstVencRoiCfg->rect.p0.y / 16;
                roi_param.roi.roi_bmby = pstVencRoiCfg->rect.p1.y / 16;
            } else {
                roi_param.roi.roi_umby = pstVencRoiCfg->rect.p1.y / 16;
                roi_param.roi.roi_bmby = pstVencRoiCfg->rect.p0.y / 16;
            }

            ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_ROI_ID, &roi_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set roi param failed, encchn:%d\n", encChn);
                return -1;
            }
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            i265e_rcfg_roi_param_t roi_param;
            memset(&roi_param, 0, sizeof(i265e_rcfg_roi_param_t));

            roi_param.idx = pstVencRoiCfg->u32Index;
            roi_param.roi.roi_en = pstVencRoiCfg->bEnable;
            roi_param.roi.roi_md = pstVencRoiCfg->bRelatedQp;
            roi_param.roi.roi_qp = pstVencRoiCfg->s32Qp;
            if (pstVencRoiCfg->rect.p0.x < pstVencRoiCfg->rect.p1.x) {
                roi_param.roi.roi_lmbx = pstVencRoiCfg->rect.p0.x / 16;
                roi_param.roi.roi_rmbx = pstVencRoiCfg->rect.p1.x / 16;
            } else {
                roi_param.roi.roi_lmbx = pstVencRoiCfg->rect.p1.x / 16;
                roi_param.roi.roi_rmbx = pstVencRoiCfg->rect.p0.x / 16;
            }

            if (pstVencRoiCfg->rect.p0.y < pstVencRoiCfg->rect.p1.y) {
                roi_param.roi.roi_umby = pstVencRoiCfg->rect.p0.y / 16;
                roi_param.roi.roi_bmby = pstVencRoiCfg->rect.p1.y / 16;
            } else {
                roi_param.roi.roi_umby = pstVencRoiCfg->rect.p1.y / 16;
                roi_param.roi.roi_bmby = pstVencRoiCfg->rect.p0.y / 16;
            }

            ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_ROI_ID, &roi_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e set roi param failed, encchn:%d\n", encChn);
                return -1;
            }
        }
#endif
    }

	return 0;
}

int IMP_Encoder_GetChnROI(int encChn, IMPEncoderROICfg *pstVencRoiCfg)
{
    int ret = 0;

    if (encChn >= NR_MAX_ENC_CHN) {
        IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
        return -1;
    }

    if ((pstVencRoiCfg == NULL) || (pstVencRoiCfg->u32Index < 0) || (pstVencRoiCfg->u32Index > 7)) {
        IMP_LOG_ERR(TAG, "Invalid Param roicfg\n");
        return -1;
    }

    EncChannel *enc_chn = &g_EncChannel[encChn];

    memset(pstVencRoiCfg, 0, sizeof(IMPEncoderROICfg));

    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_roi_param_t roi_param;
            memset(&roi_param, 0, sizeof(i264e_rcfg_roi_param_t));
            roi_param.idx = pstVencRoiCfg->u32Index;

            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_ROI_ID, &roi_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e get roi param failed,encchn:%d\n", encChn);
                return -1;
            }

            pstVencRoiCfg->u32Index = roi_param.idx;
            pstVencRoiCfg->bEnable = roi_param.roi.roi_en;
            pstVencRoiCfg->bRelatedQp = roi_param.roi.roi_md;
            pstVencRoiCfg->s32Qp = roi_param.roi.roi_qp;
            pstVencRoiCfg->rect.p0.x = roi_param.roi.roi_lmbx * 16;
            pstVencRoiCfg->rect.p0.y = roi_param.roi.roi_umby * 16;
            pstVencRoiCfg->rect.p1.x = roi_param.roi.roi_rmbx * 16;
            pstVencRoiCfg->rect.p1.y = roi_param.roi.roi_bmby * 16;
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            i265e_rcfg_roi_param_t roi_param;
            memset(&roi_param, 0, sizeof(i265e_rcfg_roi_param_t));
            roi_param.idx = pstVencRoiCfg->u32Index;

            ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_ROI_ID, &roi_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e get roi param failed,encchn:%d\n", encChn);
                return -1;
            }

            pstVencRoiCfg->u32Index = roi_param.idx;
            pstVencRoiCfg->bEnable = roi_param.roi.roi_en;
            pstVencRoiCfg->bRelatedQp = roi_param.roi.roi_md;
            pstVencRoiCfg->s32Qp = roi_param.roi.roi_qp;
            pstVencRoiCfg->rect.p0.x = roi_param.roi.roi_lmbx * 16;
            pstVencRoiCfg->rect.p0.y = roi_param.roi.roi_umby * 16;
            pstVencRoiCfg->rect.p1.x = roi_param.roi.roi_rmbx * 16;
            pstVencRoiCfg->rect.p1.y = roi_param.roi.roi_bmby * 16;

        }
#endif
    }

    return 0;
}

int IMP_Encoder_SetGOPSize(int encChn, const IMPEncoderGOPSizeCfg *pstGOPSizeCfg)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstGOPSizeCfg->gopsize < 1) {
		IMP_LOG_ERR(TAG, "Invalid Param fps:%d\n", pstGOPSizeCfg->gopsize);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    if (enc_chn) {
        pthread_mutex_lock(&enc_chn->mutex);
        enc_chn->setMaxGop = pstGOPSizeCfg->gopsize;
        pthread_mutex_unlock(&enc_chn->mutex);
    }

	return 0;
}

int IMP_Encoder_GetGOPSize(int encChn, IMPEncoderGOPSizeCfg *pstGOPSizeCfg)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_rcfg_gop_param_t gop_param;
            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_GOP_ID, &gop_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e get gop param failed, encchn:%d\n", encChn);
                return -1;
            }
            pstGOPSizeCfg->gopsize = gop_param.gopsize;
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            int gopSize = 0;
            ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_GOP_ID, &gopSize);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e get gop param failed, encchn:%d\n", encChn);
                return -1;
            }
            pstGOPSizeCfg->gopsize = gopSize;
        }
#endif
	}

	return 0;
}

int IMP_Encoder_SetChnFrmUsedMode(int encChn, const IMPEncoderAttrFrmUsed *pfrmUsedAttr)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (pfrmUsedAttr == NULL) {
		IMP_LOG_ERR(TAG, "Invalid IMPEncoderAttrFrmUsed\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	enc_chn->attr.rcAttr.attrFrmUsed = *pfrmUsedAttr;

	return 0;
}

int IMP_Encoder_GetChnFrmUsedMode(int encChn, IMPEncoderAttrFrmUsed *pfrmUsedAttr)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (pfrmUsedAttr == NULL) {
		IMP_LOG_ERR(TAG, "Invalid IMPEncoderAttrFrmUsed\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	*pfrmUsedAttr = enc_chn->attr.rcAttr.attrFrmUsed;

	return 0;
}

int IMP_Encoder_SetPadFrameAttr(int encChn, int enable, PadFrameAttr *padFrameAttr)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            if (enable) {
                memcpy(&enc_chn->padData.padAttr, padFrameAttr, sizeof(PadFrameAttr));
                enc_chn->padData.padEnable = 1;
            } else {
                enc_chn->padData.padEnable = 0;
            }
        }
    }

	return 0;
}

int IMP_Encoder_PadFrame(int encChn, IMPFrameInfo *frame, void *data, int (*releaseCallback)(IMPFrameInfo *, void *))
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		goto err_ench_chn;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if(enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		goto err_enc_chn_create;
	}

	if(frame == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid frame:%p\n", __func__, frame);
		goto err_frame;
	}

	if ((enc_chn->index < 0) || (enc_chn->recv_pic < 1)) {
		goto err_enc_chn_is_not_start;
	}

    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            if (enc_chn->padData.padEnable) {
                if (video_sem_timedwait(&enc_chn->padData.padFreeHandlerSem, &enc_chn->padData.padTimeSpec) < 0) {
                    IMP_LOG_ERR(TAG, "%s(%d):enc_chn->padData.padFreeHandlerSem failed\n", __func__, __LINE__);
                    goto err_padFreeHandlerSem;
                }
                imp_video_list_t *p_pad_elem_list = NULL;
                imp_video_pop_queue(&enc_chn->padData.padConstraints->freeListQueue, &enc_chn->padData.padConstraints->freeListQueue.queue, &p_pad_elem_list);
                if (p_pad_elem_list == NULL) {
                    IMP_LOG_ERR(TAG, "%s(%d):enc_chn->padData.padConstraints->freeListQueue is NULL\n", __func__, __LINE__);
                    goto err_freeListQueue_is_null;
                }
                imp_video_list_elem_t *p_pad_elem = container_of(p_pad_elem_list, imp_video_list_elem_t, list);
                PadStreamHandler *ppadStreamHandler = (PadStreamHandler *)p_pad_elem->data;
                ppadStreamHandler->padFrame = frame;
                ppadStreamHandler->data = data;
                ppadStreamHandler->releaseCallback = releaseCallback;
                imp_video_push_queue_tail(&enc_chn->padData.padConstraints->busyListQueue, &enc_chn->padData.padConstraints->busyListQueue.queue, p_pad_elem_list);
                sem_post(&enc_chn->padData.padBusyHandlerSem);
            } else {
                IMP_LOG_ERR(TAG, "%s:This Chn is not enable the padFrame function: %d\n", __func__, encChn);
                goto err_pad_enable;
            }
        }
    }

	return 0;

err_pad_enable:
err_freeListQueue_is_null:
err_padFreeHandlerSem:
err_enc_chn_is_not_start:
err_frame:
err_enc_chn_create:
err_ench_chn:
	releaseCallback(frame, data);
	return -1;
}

int IMP_Encoder_SetChnDenoise(int encChn, const IMPEncoderAttrDenoise *pdenoiseAttr)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_denoise_t denoise;
            denoise.i_dn_type = pdenoiseAttr->dnType;
            denoise.i_itype_qp = pdenoiseAttr->dnIQp;
            denoise.i_ptype_qp = pdenoiseAttr->dnPQp;
            if (!enc_chn->attr.rcAttr.attrDenoise.enable) {
                denoise.i_dn_type = I264E_DN_NONE;
            }
            ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_DN_ID, &denoise);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set denoise param failed, encchn:%d\n", encChn);
                return -1;
            }
            enc_chn->attr.rcAttr.attrDenoise.dnType = pdenoiseAttr->dnType;
            enc_chn->attr.rcAttr.attrDenoise.dnIQp = pdenoiseAttr->dnIQp;
            enc_chn->attr.rcAttr.attrDenoise.dnPQp = pdenoiseAttr->dnPQp;
            if (!enc_chn->attr.rcAttr.attrDenoise.enable) {
                enc_chn->attr.rcAttr.attrDenoise.dnType = I264E_DN_NONE;
            }
        } else if (enc_chn->attr.encAttr.enType == PT_H265) {
            //TODO I265E_RCFG_DN_ID, unsupported temporally
        }
    }

	return 0;
}

int IMP_Encoder_GetChnDenoise(int encChn, IMPEncoderAttrDenoise *pdenoiseAttr)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

    if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            i264e_denoise_t denoise;
            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_DN_ID, &denoise);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e get gop param failed, encchn:%d\n", encChn);
                return -1;
            }
            pdenoiseAttr->dnType = denoise.i_dn_type;
            pdenoiseAttr->dnIQp = denoise.i_itype_qp;
            pdenoiseAttr->dnPQp = denoise.i_ptype_qp;
        } else if (enc_chn->attr.encAttr.enType == PT_H265) {
            //TODO I265E_RCFG_DN_ID, unsupported temporally
        }
    }

	return 0;
}

int IMP_Encoder_SetChnHSkip(int encChn, const IMPEncoderAttrHSkip *phSkipAttr)
{
	int ret = 0;
	c_high_skip_t high_skip;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (((enc_chn->attr.encAttr.enType == PT_H264) && (phSkipAttr->skipType > enc_chn->i264e.created_align_skip_type))
            || ((enc_chn->attr.encAttr.enType == PT_H265) && (phSkipAttr->skipType > enc_chn->i265e.created_align_skip_type))) {
		IMP_LOG_ERR(TAG, "%s:unsupport the set skipType=%d for over %d to channel %d\n",
				__func__, phSkipAttr->skipType, (enc_chn->attr.encAttr.enType == PT_H264) ?
                enc_chn->i264e.created_align_skip_type : enc_chn->i265e.created_align_skip_type, encChn);
		return -1;
	}

	high_skip.i_skip_type = phSkipAttr->skipType;
	high_skip.m = phSkipAttr->m;
	high_skip.n = phSkipAttr->n;
	high_skip.max_same_scenecnt = phSkipAttr->maxSameSceneCnt;
	high_skip.b_enable_scenecut = phSkipAttr->bEnableScenecut;
	high_skip.b_black_enhance = phSkipAttr->bBlackEnhance;

	if (enc_chn->attr.encAttr.enType == PT_H264) {
        ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_HSKIP_ID, &high_skip);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e set reference skip param failed, encchn:%d\n", encChn);
            return -1;
        }
    }
#ifdef CONFIG_SOC_T30
	else if (enc_chn->attr.encAttr.enType == PT_H265) {
        ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_HSKIP_ID, &high_skip);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i265e set reference skip param failed, encchn:%d\n", encChn);
            return -1;
        }
    }
#endif

	memcpy(&enc_chn->attr.rcAttr.attrHSkip.hSkipAttr, phSkipAttr, sizeof(IMPEncoderAttrHSkip));


	return 0;
}

int IMP_Encoder_GetChnHSkip(int encChn, IMPEncoderAttrHSkip *phSkipAttr)
{
	int ret = 0;
	c_high_skip_t high_skip;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	memset(&high_skip, 0, sizeof(c_high_skip_t));
	if (enc_chn->attr.encAttr.enType == PT_H264) {
        ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_HSKIP_ID, &high_skip);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e set reference skip param failed, encchn:%d\n", encChn);
            return -1;
        }
    }
#ifdef CONFIG_SOC_T30
	else if (enc_chn->attr.encAttr.enType == PT_H265) {
        ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_HSKIP_ID, &high_skip);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i265e set reference skip param failed, encchn:%d\n", encChn);
            return -1;
        }
    }
#endif

	phSkipAttr->skipType = high_skip.i_skip_type;
	phSkipAttr->m = high_skip.m;
	phSkipAttr->n = high_skip.n;
	phSkipAttr->maxSameSceneCnt = high_skip.max_same_scenecnt;
	phSkipAttr->bEnableScenecut = high_skip.b_enable_scenecut;
	phSkipAttr->bBlackEnhance = high_skip.b_black_enhance;

	return 0;
}

int IMP_Encoder_SetChnHSkipBlackEnhance(int encChn, const int bBlackEnhance)
{
	int ret = 0;
	int b_black_enhance = !!bBlackEnhance;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (enc_chn->attr.encAttr.enType == PT_H264) {
        ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_BENHANCE_ID, &b_black_enhance);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e set hskip black enhance param failed, encchn:%d\n", encChn);
            return -1;
        }
        enc_chn->attr.rcAttr.attrHSkip.hSkipAttr.bBlackEnhance = b_black_enhance;
    }
#ifdef CONFIG_SOC_T30
	else if (enc_chn->attr.encAttr.enType == PT_H265) {
        ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_BENHANCE_ID, &b_black_enhance);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i265e set hskip black enhance param failed, encchn:%d\n", encChn);
            return -1;
        }
        enc_chn->attr.rcAttr.attrHSkip.hSkipAttr.bBlackEnhance = b_black_enhance;
    }
#endif

	return 0;
}

int IMP_Encoder_InsertUserData(int encChn, void *userData, uint32_t userDataLen)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s(%d):Invalid Channel Num:%d\n", __func__, __LINE__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index < 0) {
		IMP_LOG_ERR(TAG, "%s(%d):Encoder Channel%d hasn't been created\n", __func__, __LINE__, encChn);
		return -1;
	}

	if (enc_chn->attr.encAttr.enType == PT_JPEG) {
		IMP_LOG_ERR(TAG, "%s(%d):Encoder Channel%d isn't H264 channel\n", __func__, __LINE__, encChn);
		return -1;
	}

	if (!userData || !userDataLen) {
		IMP_LOG_ERR(TAG, "%s(%d):Channel Num=%d, invalid userData=%p, userDataLen=%d\n",
				__func__, __LINE__, encChn, userData, userDataLen);
		return -1;
	}

    if (enc_chn->attr.encAttr.enType == PT_H264) {
        if (enc_chn->i264e.userDataConstraints == NULL) {
            IMP_LOG_ERR(TAG, "%s(%d):Encoder Channel%d hasn't be create to be insertUserData Channel\n", __func__, __LINE__, encChn);
            return -1;
        }

        imp_video_list_t *p_user_data_elem_list = NULL;
        imp_video_pop_queue(&enc_chn->i264e.userDataConstraints->freeListQueue, &enc_chn->i264e.userDataConstraints->freeListQueue.queue, &p_user_data_elem_list);
        if (p_user_data_elem_list == NULL) {
            imp_video_pop_queue(&enc_chn->i264e.userDataConstraints->doneListQueue, &enc_chn->i264e.userDataConstraints->doneListQueue.queue, &p_user_data_elem_list);
            if (p_user_data_elem_list == NULL) {
                IMP_LOG_WARN(TAG, "%s(%d):Channel Num=%d han't empty cache userData buf to accept the userData, please wait seconds\n",
                        __func__, __LINE__, encChn);
                return -1;
            }
        }

        imp_video_list_elem_t *p_user_data_elem = container_of(p_user_data_elem_list, imp_video_list_elem_t, list);
        if (userDataLen > (p_user_data_elem->dataSize - 20)) {
            imp_video_push_queue_tail(&enc_chn->i264e.userDataConstraints->freeListQueue, &enc_chn->i264e.userDataConstraints->freeListQueue.queue, p_user_data_elem_list);
            IMP_LOG_WARN(TAG, "%s(%d):Channel Num=%d userDataLen(%u)>(elem->dataSize(%d) - 16)\n",
                    __func__, __LINE__, encChn, userDataLen, p_user_data_elem->dataSize);
            return -1;
        }

        static const uint8_t userDataUuid[16] = {
            0xd7, 0x3e, 0xba, 0x3d, 0xe6, 0xa6, 0x4c, 0x80,
            0x93, 0x79, 0x64, 0x0b, 0x42, 0xf2, 0xb8, 0x66,
        };
        *((uint32_t *)p_user_data_elem->data) = userDataLen + 16;
        memcpy(p_user_data_elem->data + 4, userDataUuid, 16);
        memcpy(p_user_data_elem->data + 20, userData, userDataLen);
        imp_video_push_queue_tail(&enc_chn->i264e.userDataConstraints->busyListQueue, &enc_chn->i264e.userDataConstraints->busyListQueue.queue, p_user_data_elem_list);
    } else if (enc_chn->attr.encAttr.enType == PT_H265) {
        if (enc_chn->i265e.userDataConstraints == NULL) {
            IMP_LOG_ERR(TAG, "%s(%d):Encoder Channel%d hasn't be create to be insertUserData Channel\n", __func__, __LINE__, encChn);
            return -1;
        }

        imp_video_list_t *p_user_data_elem_list = NULL;
        imp_video_pop_queue(&enc_chn->i265e.userDataConstraints->freeListQueue, &enc_chn->i265e.userDataConstraints->freeListQueue.queue, &p_user_data_elem_list);
        if (p_user_data_elem_list == NULL) {
            imp_video_pop_queue(&enc_chn->i265e.userDataConstraints->doneListQueue, &enc_chn->i265e.userDataConstraints->doneListQueue.queue, &p_user_data_elem_list);
            if (p_user_data_elem_list == NULL) {
                IMP_LOG_WARN(TAG, "%s(%d):Channel Num=%d han't empty cache userData buf to accept the userData, please wait seconds\n",
                        __func__, __LINE__, encChn);
                return -1;
            }
        }

        imp_video_list_elem_t *p_user_data_elem = container_of(p_user_data_elem_list, imp_video_list_elem_t, list);
        if (userDataLen > (p_user_data_elem->dataSize - 20)) {
            imp_video_push_queue_tail(&enc_chn->i265e.userDataConstraints->freeListQueue, &enc_chn->i265e.userDataConstraints->freeListQueue.queue, p_user_data_elem_list);
            IMP_LOG_WARN(TAG, "%s(%d):Channel Num=%d userDataLen(%u)>(elem->dataSize(%d) - 16)\n",
                    __func__, __LINE__, encChn, userDataLen, p_user_data_elem->dataSize);
            return -1;
        }

        *((uint32_t *)p_user_data_elem->data) = userDataLen;
        memcpy(p_user_data_elem->data + 4, userData, userDataLen);
        imp_video_push_queue_tail(&enc_chn->i265e.userDataConstraints->busyListQueue, &enc_chn->i265e.userDataConstraints->busyListQueue.queue, p_user_data_elem_list);
    }

	return 0;
}

int IMP_Encoder_SetChnResizeMode(int encChn, int en)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}
	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}
	if (en) {
		enc_chn->resize_AtoA = 1;
	}
	else {
		enc_chn->resize_AtoA = 0;
	}
	return 0;
}

int IMP_Encoder_SetPoolSize(int size)
{
	IMP_LOG_INFO(TAG, "IMP_Encoder_SetPoolSize:%d\n", size);
	if (size <= 0)
		return -1;
	encoder_bs_buf_size = size;
	return 0;
}

int IMP_Encoder_SetMbRC(int encChn, int bEnable)
{
	int ret = 0;
    int b_enable = !!bEnable;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (enc_chn->attr.encAttr.enType == PT_H264) {
        ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_MBRC_ID, &b_enable);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e %s mb ratecontrol failed, encchn:%d\n", b_enable? "open" : "close", encChn);
            return -1;
        }
    } else if (enc_chn->attr.encAttr.enType == PT_H265) {
        //TODO I265E_RCFG_MBRC_ID, unsupported temporally, move to qpgmode
    }

    return 0;
}

int IMP_Encoder_GetMbRC(int encChn, int *bEnable)
{
	int ret = 0;
    int b_enable = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (enc_chn->attr.encAttr.enType == PT_JPEG) {
		IMP_LOG_ERR(TAG, "%s:unsupport to set mb ratecontrol channel:%d\n", __func__, encChn);
		return -1;
	}

    if (enc_chn->attr.encAttr.enType == PT_H264) {
        ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_MBRC_ID, &b_enable);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e get mb ratecontrol param failed, encchn:%d\n", encChn);
            return -1;
        }
    } else if (enc_chn->attr.encAttr.enType == PT_H265) {
        //TODO I265E_RCFG_MBRC_ID, unsupported temporally, move to qpgmode
    }

    *bEnable = !!b_enable;

    return 0;
}

int IMP_Encoder_SetChangeRef(int encChn, int bEnable)
{
	int ret = 0;
    int b_enable = !!bEnable;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (enc_chn->attr.encAttr.enType == PT_JPEG) {
		IMP_LOG_ERR(TAG, "%s:unsupport to set change ref channel:%d\n", __func__, encChn);
		return -1;
	}

	if (enc_chn->attr.encAttr.enType == PT_H264) {
        ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_CHGREF_ID, &b_enable);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e %s change ref failed, encchn:%d\n", b_enable? "open" : "close", encChn);
            return -1;
        }
    } else if (enc_chn->attr.encAttr.enType == PT_H265) {
        //TODO, I265E_RCFG_CHGREF_ID, unsupported temporally
    }

    return 0;
}

int IMP_Encoder_GetChangeRef(int encChn, int *bEnable)
{
	int ret = 0;
    int b_enable = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn == NULL) {
		IMP_LOG_ERR(TAG, "%s:Invalid Channel Num:%d\n", __func__, encChn);
		return -1;
	}

	if (enc_chn->attr.encAttr.enType != PT_JPEG) {
		IMP_LOG_ERR(TAG, "%s:unsupport to change ref channel:%d\n", __func__, encChn);
		return -1;
	}

    if (enc_chn->attr.encAttr.enType == PT_H264) {
        ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_CHGREF_ID, &b_enable);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e get change ref param failed, encchn:%d\n", encChn);
            return -1;
        }
    } else if (enc_chn->attr.encAttr.enType == PT_H265) {
        //TODO, I265E_RCFG_CHGREF_ID, unsupported temporally
    }

    *bEnable = !!b_enable;

    return 0;
}

int IMP_Encoder_SetSuperFrameCfg(int encChn, const IMPEncoderSuperFrmCfg *pstSuperFrmParam)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstSuperFrmParam == NULL) {
		IMP_LOG_ERR(TAG, "pstSuperFrmParam is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (enc_chn) {
        c_superfrm_param_t superfrm_param;

        superfrm_param.mode = pstSuperFrmParam->superFrmMode;
		if (pstSuperFrmParam->superIFrmBitsThr < (enc_chn->attr.encAttr.bufSize - 8192 - 64 * 2) * 8) {
			superfrm_param.iframe_bits_thresd = pstSuperFrmParam->superIFrmBitsThr;
		} else {
			superfrm_param.iframe_bits_thresd = (enc_chn->attr.encAttr.bufSize - 8192 - 64 * 2) * 8;
		}
        superfrm_param.pframe_bits_thresd = pstSuperFrmParam->superPFrmBitsThr;
        superfrm_param.bframe_bits_thresd = pstSuperFrmParam->superBFrmBitsThr;
        superfrm_param.priority = pstSuperFrmParam->rcPriority;

        if (enc_chn->attr.encAttr.enType == PT_H264) {
            ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_SUPER_ID, &superfrm_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e set super frame param failed, encchn:%d\n", encChn);
                return -1;
            }
        }
#ifdef CONFIG_SOC_T30
		else if (enc_chn->attr.encAttr.enType == PT_H265) {
            ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_SUPER_ID, &superfrm_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e set super frame param failed, encchn:%d\n", encChn);
                return -1;
            }
        }
#endif
	}

	return 0;
}

int IMP_Encoder_GetSuperFrameCfg(int encChn, IMPEncoderSuperFrmCfg *pstSuperFrmParam)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstSuperFrmParam == NULL) {
		IMP_LOG_ERR(TAG, "pstSuperFrmParam is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
    c_superfrm_param_t superfrm_param;

	if (enc_chn) {
        if (enc_chn->attr.encAttr.enType == PT_H264) {
            ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_SUPER_ID, &superfrm_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i264e get super frame param failed, encchn:%d\n", encChn);
                return -1;
            }
            pstSuperFrmParam->superFrmMode = superfrm_param.mode;
            pstSuperFrmParam->superIFrmBitsThr = superfrm_param.iframe_bits_thresd;
            pstSuperFrmParam->superPFrmBitsThr = superfrm_param.pframe_bits_thresd;
            pstSuperFrmParam->superBFrmBitsThr = superfrm_param.bframe_bits_thresd;
            pstSuperFrmParam->rcPriority = superfrm_param.priority;
        }
#ifdef CONFIG_SOC_T30
		if (enc_chn->attr.encAttr.enType == PT_H265) {
            ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_SUPER_ID, &superfrm_param);
            if (ret != 0) {
                IMP_LOG_ERR(TAG, "i265e get super frame param failed, encchn:%d\n", encChn);
                return -1;
            }
            pstSuperFrmParam->superFrmMode = superfrm_param.mode;
            pstSuperFrmParam->superIFrmBitsThr = superfrm_param.iframe_bits_thresd;
            pstSuperFrmParam->superPFrmBitsThr = superfrm_param.pframe_bits_thresd;
            pstSuperFrmParam->superBFrmBitsThr = superfrm_param.bframe_bits_thresd;
            pstSuperFrmParam->rcPriority = superfrm_param.priority;
        }
#endif
	}

    return 0;
}

int IMP_Encoder_SetH264TransCfg(int encChn, const IMPEncoderH264TransCfg *pstH264TransCfg)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstH264TransCfg == NULL) {
		IMP_LOG_ERR(TAG, "pstH264TransCfg is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H264)) {
        int chroma_qp_offset = pstH264TransCfg->chroma_qp_index_offset;

        ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_TRANS_ID, &chroma_qp_offset);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i264e set transform param failed, encchn:%d\n", encChn);
            return -1;
        }
    }

	return 0;
}

int IMP_Encoder_GetH264TransCfg(int encChn, IMPEncoderH264TransCfg *pstH264TransCfg)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstH264TransCfg == NULL) {
		IMP_LOG_ERR(TAG, "pstH264TransCfg is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    memset(pstH264TransCfg, 0, sizeof(IMPEncoderH264TransCfg));

	if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H264)) {
		ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_TRANS_ID, &pstH264TransCfg->chroma_qp_index_offset);
		if (ret != 0) {
			IMP_LOG_ERR(TAG, "i264e get transform param failed, encchn:%d\n", encChn);
			return -1;
		}
	}
    return 0;
}

int IMP_Encoder_SetH265TransCfg(int encChn, const IMPEncoderH265TransCfg *pstH265TransCfg)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstH265TransCfg == NULL) {
		IMP_LOG_ERR(TAG, "pstH265TransCfg is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
#ifdef CONFIG_SOC_T30
    if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H265)) {
        i265e_rcfg_trans_param_t trans;

        memset(&trans, 0, sizeof(i265e_rcfg_trans_param_t));
        trans.cbQpOffset = pstH265TransCfg->chroma_cb_qp_offset;
        trans.crQpOffset = pstH265TransCfg->chroma_cr_qp_offset;

        ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_TRANS_ID, &trans);
        if (ret != 0) {
            IMP_LOG_ERR(TAG, "i265e set transform param failed, encchn:%d\n", encChn);
            return -1;
        }
    }
#endif

	return 0;
}

int IMP_Encoder_GetH265TransCfg(int encChn, IMPEncoderH265TransCfg *pstH265TransCfg)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstH265TransCfg == NULL) {
		IMP_LOG_ERR(TAG, "pstH265TransCfg is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    memset(pstH265TransCfg, 0, sizeof(IMPEncoderH265TransCfg));
#ifdef CONFIG_SOC_T30
	if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H265)) {
        i265e_rcfg_trans_param_t trans;

		ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_TRANS_ID, &trans);
		if (ret != 0) {
			IMP_LOG_ERR(TAG, "i265e get transform param failed, encchn:%d\n", encChn);
			return -1;
		}
        pstH265TransCfg->chroma_cb_qp_offset = trans.cbQpOffset;
        pstH265TransCfg->chroma_cr_qp_offset = trans.crQpOffset;
	}
#endif
    return 0;
}

int IMP_Encoder_SetQpgMode(int encChn, const IMPEncoderQpgMode *pstQpgMode)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstQpgMode == NULL) {
		IMP_LOG_ERR(TAG, "pstQpgMode is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H264)) {
        int qpgmode = *pstQpgMode;

		ret = i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_QPGMODE_ID, &qpgmode);
		if (ret != 0) {
			IMP_LOG_ERR(TAG, "i264e set qpgmode  param failed, encchn:%d\n", encChn);
			return -1;
		}
    }
#ifdef CONFIG_SOC_T30
	else if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H265)) {
        int qpgmode = *pstQpgMode;

		ret = i265e_set_param(enc_chn->i265e.i265eHandler, I265E_RCFG_QPGMODE_ID, &qpgmode);
		if (ret != 0) {
			IMP_LOG_ERR(TAG, "i265e set qpgmode  param failed, encchn:%d\n", encChn);
			return -1;
		}
	}
#endif

	return 0;
}

int IMP_Encoder_GetQpgMode(int encChn, IMPEncoderQpgMode *pstQpgMode)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstQpgMode == NULL) {
		IMP_LOG_ERR(TAG, "pstQpgMode is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

	if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H264)) {
		ret = i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_QPGMODE_ID, pstQpgMode);
		if (ret != 0) {
			IMP_LOG_ERR(TAG, "i264e get qpgmode param failed, encchn:%d\n", encChn);
			return -1;
		}
    }
#ifdef CONFIG_SOC_T30
	else if (enc_chn && (enc_chn->attr.encAttr.enType == PT_H265)) {
		ret = i265e_get_param(enc_chn->i265e.i265eHandler, I265E_RCFG_QPGMODE_ID, pstQpgMode);
		if (ret != 0) {
			IMP_LOG_ERR(TAG, "i265e get qpgmode param failed, encchn:%d\n", encChn);
			return -1;
		}
	}
#endif
    return 0;
}

int IMP_Encoder_SetJpegeQl(int encChn, const IMPEncoderJpegeQl *pstJpegeQl)
{
	int ret = 0;

	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstJpegeQl == NULL) {
		IMP_LOG_ERR(TAG, "pstJpegeQl is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
    ijpege_ql_param_t jpegeQl;
    jpegeQl.user_ql_en = pstJpegeQl->user_ql_en;
    memcpy(jpegeQl.qmem_table,pstJpegeQl->qmem_table,sizeof(jpegeQl.qmem_table));
	if (enc_chn) {
		ret = ijpege_set_param(enc_chn->jpege.ijpegeHandler,IJPEGE_RCFG_QL_ID , &jpegeQl);
		if (ret != 0) {
		IMP_LOG_ERR(TAG, "ijpege set ql param failed, encchn:%d\n", encChn);
			return -1;
		}
    }
	return 0;
}

int IMP_Encoder_GetJpegeQl(int encChn, IMPEncoderJpegeQl *pstJpegeQl)
{
	int ret = 0;
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num:%d\n", encChn);
		return -1;
	}

	if (pstJpegeQl == NULL) {
		IMP_LOG_ERR(TAG, "pstJpegeQl is null\n");
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];

    memset(pstJpegeQl, 0, sizeof(IMPEncoderJpegeQl));
    ijpege_ql_param_t jpegeQl;
	if (enc_chn) {
		ret = ijpege_get_param(enc_chn->jpege.ijpegeHandler, IJPEGE_RCFG_QL_ID, &jpegeQl);
		if (ret != 0) {
			IMP_LOG_ERR(TAG, "ijpege get ql param failed, encchn:%d\n", encChn);
			return -1;
		}
        pstJpegeQl->user_ql_en = jpegeQl.user_ql_en;
        memcpy(pstJpegeQl->qmem_table,jpegeQl.qmem_table,sizeof(jpegeQl.qmem_table));
	}
    return 0;
}

int IMP_Encoder_SetRdBufShare(int encChn, int bEnable)
{
	if (encChn >= NR_MAX_ENC_CHN) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", encChn);
		return -1;
	}

	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn->index >= 0) {
		IMP_LOG_ERR(TAG, "Max StreamCnt must be set before channel created, encChn=%d\n", encChn);
		return -1;
	}
	enc_chn->b_enable_bufshare = !!bEnable;

	return 0;
}

static const int jpeg_chroma_quantizer_Imp[64] = {
	17, 18, 24, 47, 99, 99, 99, 99,
	18, 21, 26, 66, 99, 99, 99, 99,
	24, 26, 56, 99, 99, 99, 99, 99,
	47, 66, 99, 99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99,
	99, 99, 99, 99, 99, 99, 99, 99
};

static const int jpeg_luma_quantizer_Imp[64] = {
	16, 11, 10, 16, 24, 40, 51, 61,
	12, 12, 14, 19, 26, 58, 60, 55,
	14, 13, 16, 24, 40, 57, 69, 56,
	14, 17, 22, 29, 51, 87, 80, 62,
	18, 22, 37, 56, 68, 109, 103, 77,
	24, 35, 55, 64, 81, 104, 113, 92,
	49, 64, 78, 87, 103, 121, 120, 101,
	72, 92, 95, 98, 112, 100, 103, 99
};
/*改变q的值可得到不同质量的jpeg,q越大jpeg质量越好，q的范围1~99*/
void MakeTables_Imp(int q, uint8_t *lqt, uint8_t *cqt)
{
    int i;
    int factor = q;
    if (q < 1) factor = 1;
    if (q > 99) factor = 99;
    if (q < 50)
        q = 5000 / factor;
    else
        q = 200 - factor*2;
    for (i=0; i < 64; i++) {
        int lq = (jpeg_luma_quantizer_Imp[i] * q + 50) / 100;
        int cq = (jpeg_chroma_quantizer_Imp[i] * q + 50) / 100;
        /* Limit the quantizers to 1 <= q <= 255 */
        if (lq < 1) lq = 1;
        else if (lq > 255) lq = 255;
        lqt[i] = lq;
        if (cq < 1) cq = 1;
        else if (cq > 255) cq = 255;
        cqt[i] = cq;
    }
}

int IMP_Encoder_InputJpege(uint8_t *src, uint8_t *dst, int src_w, int src_h, int q, int *stream_length)
{
	ijpege_param_t ijpege_param;
	ijpege_t *ijpege_handler;
	int i_nal;
	unsigned int jpeg_status = 0;
	ijpege_nal_t *nal;
	ijpege_pic_t pic_in,pic_out;
	ijpege_ql_param_t jpegeQl;

	if ((src_w%32 != 0) || (src_h%8 != 0)) {
		printf("width=%d must be multiples of 32 and height=%d must be multiples of 8\n", src_w, src_h);
		IMP_LOG_ERR(TAG, "%s: width=%d must be multiples of 32 and height=%d must be multiples of 8\n", __func__, src_w, src_h);
		return -1;
	}
	ijpege_param_default(&ijpege_param);
	ijpege_param.soc = C_T23;

	ijpege_param.i_width = src_w;
	ijpege_param.i_height = src_h;

	ijpege_param.ckmalloc = video_vbm_malloc;
	ijpege_param.ckfree = video_vbm_free;
	ijpege_param.ckvirt_to_phys = video_vbm_virt_to_phys;
	ijpege_param.ckphys_to_virt = video_vbm_phys_to_virt;
	ijpege_param.b_tlb = 0;
	ijpege_param.b_use_phy = 1;
	ijpege_param.i_csp = C_CSP_NV12; /* NV12 only */

	ijpege_handler = ijpege_init(&ijpege_param);
	if (ijpege_handler == NULL) {
		IMP_LOG_ERR(TAG, "JPEG Encoder open failed\n");
		return -1;
	}

	if (q != 0) {
		ijpege_get_param(ijpege_handler, IJPEGE_RCFG_QL_ID, &jpegeQl);
		MakeTables_Imp(q, &(jpegeQl.qmem_table[0]), &(jpegeQl.qmem_table[64]));
		jpegeQl.user_ql_en = 1;
		ijpege_set_param(ijpege_handler, IJPEGE_RCFG_QL_ID, &jpegeQl);
	}

	memset(&pic_in, 0, sizeof(ijpege_pic_t));
	pic_in.img.i_csp = ijpege_param.i_csp;
	pic_in.i_ql = PT_JPEG;
	pic_in.i_pic_struct = C_PIC_STRUCT_AUTO;
	pic_in.img.i_plane = 2;

	pic_in.img.i_stride[0] = pic_in.img.i_stride[1] = C_ALIGN(ijpege_param.i_width, 16);
	pic_in.img.i_lines[0] = C_ALIGN(ijpege_param.i_height, 16);
	pic_in.img.i_lines[1] = C_ALIGN(ijpege_param.i_height, 16) / 2;

	pic_in.img.plane[0] = src;
	pic_in.img.plane[1] = pic_in.img.plane[0] + ijpege_param.i_width * ijpege_param.i_height;

	ijpege_handler->out.nal.p_payload = dst;

	ijpege_encode(ijpege_handler, &nal, &i_nal, &pic_in, &pic_out);
	*stream_length = nal->i_payload;

	ijpege_deinit(ijpege_handler);

	return 0;
}

#if 0
static int save_stream(int fd, int chnNum, IMPEncoderStream *stream)
{
	int ret, i, nr_pack = stream->packCount;

	for (i = 0; i < nr_pack; i++) {
		//printf("channel%d stream write nr_pack:%d,size:%d\n", chnNum, i, stream->pack[i].length);
		ret = write(fd, (void *)stream->pack[i].virAddr,
					stream->pack[i].length);
		if (ret != stream->pack[i].length) {
			IMP_LOG_ERR(TAG, "channel%d stream write error:%s\n", chnNum, strerror(errno));
			return -1;
		}
	}

	return 0;
}
#endif

/* below is for debug */


#define IMPDBG_FMT_STRUCT_DEPTH 20
#define IMPDBG_FMT_STRUCT_ITEM_NAME 50

int IMPDbgFmtItem(int8_t **ppbuf, int32_t *psize, void *pparentdata, void *pchilddata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int8_t depth, int8_t *dataname, int32_t datasize)
{
	uint32_t nowdepth = depth;
	uint32_t retsize = 0;
	uint32_t i = 0;
	char *pbuf = (char *)*ppbuf;
	uint32_t bufsize = *psize;
	uint32_t data = 0;

	for (i = 0; i <= nowdepth; i++) {
		//printf("##### i = %d nowdepth = %d\n", i, nowdepth);
		if (bufsize < 1) {
			printf("err(%s%d): out of buf leftbuf = %d\n", __FILE__, __LINE__, bufsize);
			return -1;
		}
		pbuf = (char *)*ppbuf;
		retsize = snprintf(pbuf, bufsize, "%s->", info[i]);
		if (retsize >= bufsize) {
			printf("err(%s%d): out of buf retsize = %d, size = %d\n", __FILE__, __LINE__, retsize, bufsize);
			return -1;
		}
		*ppbuf += retsize;
		*psize = bufsize - retsize;
		bufsize = *psize;
	}
	if (bufsize < 1) {
		printf("err(%s%d): out of buf leftbuf = %d\n", __FILE__, __LINE__, bufsize);
		return -1;
	}
	if (1 == datasize) {
		data = *(int8_t*)pchilddata;
	} else if (2 == datasize) {
		data = *(int16_t*)pchilddata;
	} else if (4 == datasize) {
		data = *(int32_t*)pchilddata;
	} else {
		printf("err(%s%d): not support data size\n", __FILE__, __LINE__);
	}
	pbuf = (char *)*ppbuf;
	retsize = snprintf(pbuf, bufsize, "%s = %d(0x%x) offset:size = %d:%d\n", (char *)dataname, data, data, pchilddata-pparentdata, datasize);
	if (retsize >= bufsize) {
		printf("err(%s%d): out of buf retsize = %d, size = %d\n", __FILE__, __LINE__, retsize, bufsize);
		return -1;
	}
	//printf("info(%s%d): retsize = %d, size = %d\n", __FILE__, __LINE__, retsize, bufsize);
	*ppbuf += retsize;
	*psize = bufsize - retsize;
	return 0;
}

int IMPDbgUpdateInfo(int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth, int8_t *name)
{
	uint32_t retsize = 0;
	uint32_t size = 0;
	size = IMPDBG_FMT_STRUCT_ITEM_NAME;
	retsize = snprintf((char *)info[depth], size, (char *)name);
	if (retsize >= size) {
		printf("err(%s%d): out of buf retsize = %d, size = %d\n", __FILE__, __LINE__, retsize, size);
		return -1;
	}
	return 0;
}

#define IMPDBG_FMT_ITEM(top_data, parent_data, parent_type, child_item) \
	IMPDbgFmtItem(ppbuf, psize, top_data, &((parent_type *)parent_data)->child_item, info, depth, (int8_t *)#child_item, sizeof(((parent_type *)parent_data)->child_item));

int IMPDbgFmtEncoderFrmRate(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"outFrmRate");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderFrmRate, frmRateNum);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderFrmRate, frmRateDen);
	return 0;
}

int IMPDbgFmtEncoderAttrH264FixQP(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"FixQP");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264FixQP, qp);
	return 0;
}

int IMPDbgFmtEncoderAttrH264CBR(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"Cbr");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, maxQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, minQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, outBitRate);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, iBiasLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, frmQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, gopQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, adaptiveMode);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264CBR, gopRelation);
	return 0;
}

int IMPDbgFmtEncoderAttrH264VBR(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"Vbr");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, maxQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, minQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, staticTime);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, maxBitRate);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, iBiasLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, changePos);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, qualityLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, frmQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, gopQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264VBR, gopRelation);
	return 0;
}

int IMPDbgFmtEncoderAttrH264Smart(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"Smart");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, maxQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, minQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, staticTime);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, maxBitRate);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, iBiasLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, changePos);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, qualityLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, frmQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, gopQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH264Smart, gopRelation);
	return 0;
}

int IMPDbgFmtEncoderAttrH265FixQP(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"FixQP");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265FixQP, qp);
	return 0;
}

int IMPDbgFmtEncoderAttrH265CBR(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"Cbr");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, maxQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, minQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, staticTime);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, outBitRate);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, iBiasLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, frmQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, gopQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265CBR, flucLvl);
	return 0;
}

int IMPDbgFmtEncoderAttrH265VBR(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"Vbr");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, maxQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, minQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, staticTime);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, maxBitRate);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, iBiasLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, changePos);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, qualityLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, frmQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, gopQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265VBR, flucLvl);
	return 0;
}

int IMPDbgFmtEncoderAttrH265Smart(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"Smart");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, maxQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, minQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, staticTime);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, maxBitRate);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, iBiasLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, changePos);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, qualityLvl);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, frmQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, gopQPStep);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrH265Smart, flucLvl);
	return 0;
}

int IMPDbgFmtEncoderAttrRcMode(int chnNum, int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth, IMPPayloadType encType)
{
	uint32_t nextdepth = depth + 1;

	IMPDbgUpdateInfo(info, depth, (int8_t*)"rcMode");
	IMP_Encoder_GetChnAttrRcMode(chnNum, (IMPEncoderAttrRcMode *)psubdata);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrRcMode, rcMode);
    if (encType == PT_H264) {
 		if (ENC_RC_MODE_FIXQP == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
			IMPDbgFmtEncoderAttrH264FixQP(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH264FixQp,info, nextdepth);
		} else if (ENC_RC_MODE_CBR == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
			IMPDbgFmtEncoderAttrH264CBR(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH264Cbr,info, nextdepth);
		} else if (ENC_RC_MODE_VBR == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
			IMPDbgFmtEncoderAttrH264VBR(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH264Vbr,info, nextdepth);
		} else if (ENC_RC_MODE_SMART == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
			IMPDbgFmtEncoderAttrH264Smart(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH264Smart,info, nextdepth);
		}
    } else if (encType == PT_H265) {
        if (ENC_RC_MODE_FIXQP == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
            IMPDbgFmtEncoderAttrH265FixQP(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH265FixQp,info, nextdepth);
        } else if (ENC_RC_MODE_CBR == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
            IMPDbgFmtEncoderAttrH265CBR(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH265Cbr,info, nextdepth);
        } else if (ENC_RC_MODE_VBR == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
            IMPDbgFmtEncoderAttrH265VBR(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH265Vbr,info, nextdepth);
        } else if (ENC_RC_MODE_SMART == ((IMPEncoderAttrRcMode *)psubdata)->rcMode) {
            IMPDbgFmtEncoderAttrH265Smart(ppbuf, psize, pdata, &((IMPEncoderAttrRcMode *)psubdata)->attrH265Smart,info, nextdepth);
        }
    }

    return 0;
}

int IMPDbgFmtEncoderAttrFrmUsed(int chnNum, int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"frmUsed");
	IMP_Encoder_GetChnFrmUsedMode(chnNum, (IMPEncoderAttrFrmUsed *)psubdata);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrFrmUsed, enable);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrFrmUsed, frmUsedMode);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrFrmUsed, frmUsedTimes);

	return 0;
}

int IMPDbgFmtEncoderAttrDenoise(int chnNum, int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"denoise");
	IMP_Encoder_GetChnDenoise(chnNum, (IMPEncoderAttrDenoise *)psubdata);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrDenoise, enable);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrDenoise, dnType);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrDenoise, dnIQp);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrDenoise, dnPQp);

	return 0;
}

int IMPDbgFmtEncoderAttrHSkip(int chnNum, int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"hSkipAttr");
	IMP_Encoder_GetChnHSkip(chnNum, (IMPEncoderAttrHSkip *)psubdata);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrHSkip, skipType);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrHSkip, m);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrHSkip, n);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrHSkip, maxSameSceneCnt);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrHSkip, bEnableScenecut);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrHSkip, bBlackEnhance);

	return 0;
}

int IMPDbgFmtEncoderAttrInitHSkip(int chnNum, int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	uint32_t nextdepth = depth + 1;
	IMPDbgUpdateInfo(info, depth, (int8_t*)"hSkip");
	IMPDbgFmtEncoderAttrHSkip(chnNum, ppbuf, psize, pdata, &((IMPEncoderAttrInitHSkip*)psubdata)->hSkipAttr, info, nextdepth);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttrInitHSkip, maxHSkipType);

	return 0;
}

int IMPDbgFmtEncoderEncHelixAttr(int8_t **ppbuf, int32_t *psize, void *pdata, void *psubdata, int8_t (*                    info)[IMPDBG_FMT_STRUCT_ITEM_NAME], int depth)
{
	IMPDbgUpdateInfo(info, depth, (int8_t*)"encAttr");
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttr, profile);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttr, picWidth);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttr, picHeight);
	IMPDBG_FMT_ITEM(pdata, psubdata, IMPEncoderAttr, bufSize);
	return 0;
}

int IMPDbgFmtEncoderHelixAttr(int8_t **ppbuf, int32_t *psize, EncChannel *ch)
{
	uint32_t depth = 0;
	uint32_t nextdepth = depth+1;
	int8_t info[IMPDBG_FMT_STRUCT_DEPTH][IMPDBG_FMT_STRUCT_ITEM_NAME];
	void *pdata = &ch->attr;
	IMPDbgUpdateInfo(info, depth, (int8_t*)"chnAttr");
	IMPDbgFmtEncoderEncHelixAttr(ppbuf, psize, pdata, &((IMPEncoderCHNAttr *)pdata)->encAttr, info, nextdepth);
	IMPDbgFmtEncoderFrmRate(ppbuf, psize, pdata, &((IMPEncoderCHNAttr *)pdata)->rcAttr.outFrmRate,info, nextdepth);
	return 0;
}

int IMPDbgFmtEncoderRcAttr(int8_t **ppbuf, int32_t *psize, EncChannel *ch)
{
	uint32_t depth = 0;
	uint32_t nextdepth = depth+1;
	int8_t info[IMPDBG_FMT_STRUCT_DEPTH][IMPDBG_FMT_STRUCT_ITEM_NAME];
	void *pdata = &ch->attr.rcAttr;
	IMPPayloadType encType = ch->attr.encAttr.enType;
	IMPDbgUpdateInfo(info, depth, (int8_t*)"rcAttr");
	IMPDbgFmtEncoderFrmRate(ppbuf, psize, pdata, &((IMPEncoderRcAttr *)pdata)->outFrmRate, info, nextdepth);
	IMPDBG_FMT_ITEM(pdata, pdata, IMPEncoderRcAttr, maxGop);
	IMPDbgFmtEncoderAttrRcMode(ch->index, ppbuf, psize, pdata, &((IMPEncoderRcAttr *)pdata)->attrRcMode, info, nextdepth, encType);
	IMPDbgFmtEncoderAttrFrmUsed(ch->index, ppbuf, psize, pdata, &((IMPEncoderRcAttr *)pdata)->attrFrmUsed,info, nextdepth);
	IMPDbgFmtEncoderAttrDenoise(ch->index, ppbuf, psize, pdata, &((IMPEncoderRcAttr *)pdata)->attrDenoise,info, nextdepth);
	IMPDbgFmtEncoderAttrInitHSkip(ch->index, ppbuf, psize, pdata, &((IMPEncoderRcAttr *)pdata)->attrHSkip,info, nextdepth);

	return 0;
}

int IMPDbgFmtEncoderSuperFrmInfoGet(int8_t **ppbuf, int32_t *psize, EncChannel *ch)
{
	uint32_t depth = 0;
	//uint32_t nextdepth = depth+1;
	int8_t info[IMPDBG_FMT_STRUCT_DEPTH][IMPDBG_FMT_STRUCT_ITEM_NAME];IMPEncoderSuperFrmCfg pstSuperFrmParam;
    IMP_Encoder_GetSuperFrameCfg(ch->index, &pstSuperFrmParam);
	void *pdata = &pstSuperFrmParam;
    IMPDbgUpdateInfo(info, depth, (int8_t*)"superFrmCfg");
	IMPDBG_FMT_ITEM(pdata, pdata, IMPEncoderSuperFrmCfg, superFrmMode);
	IMPDBG_FMT_ITEM(pdata, pdata, IMPEncoderSuperFrmCfg, superIFrmBitsThr);
	IMPDBG_FMT_ITEM(pdata, pdata, IMPEncoderSuperFrmCfg, superPFrmBitsThr);
	IMPDBG_FMT_ITEM(pdata, pdata, IMPEncoderSuperFrmCfg, superBFrmBitsThr);
	IMPDBG_FMT_ITEM(pdata, pdata, IMPEncoderSuperFrmCfg, rcPriority);

	return 0;
}

typedef struct dbg_enc_info_data {
	int	bnorc;
} dbg_enc_info_data_t;

int dbg_enc_info(void *buf, int msize, void **arg)
{
	int i,j;
	dformat *df = buf;
	int len = 0;
	int tlen = 0;
	char *dbuf = NULL;
	int sizeParam = 0;
	dbg_enc_info_data_t *pparam;
	int bnorc = 0;

	if (NULL == gEncoder) {
		df->out.ret = -1;
		return -1;
	}

	pparam = (dbg_enc_info_data_t *)df->in.udf;
	sizeParam = df->in.size;
	if (sizeParam >= sizeof(dbg_enc_info_data_t)) {
		bnorc = pparam->bnorc;
	}

	dbuf = (char *)df->out.udf;
	Device *dev = gEncoder->device;
	int gnr = dev->nr_groups;
	for (i = 0; i < gnr; i++) {
		Group *pg = dev->groups[i];
		if (NULL != pg) {
			EncGroup *pencg = &gEncoder->encGroup[i];
			len = sprintf(dbuf, "GROUP %d\n", i);
			dbuf += len;
			tlen += len;
			for (j = 0; j < NR_MAX_ENC_CHN_IN_GROUP; j++) {
				EncChannel *ch = pencg->channel[j];
				if (NULL != ch)
					if (-1 != ch->index) {
						int tmplen = 2000;
						len = sprintf(dbuf, "\tCHANNEL %d   %5dx%5d  %8s %s tf:%-10d df:%-10d encdur:%lld, encodingFrameCnt:%lld,endencodeFrameCnt=%lld,endrelaseFrameCnt=%lld\n",
								ch->index, ch->attr.encAttr.picWidth, ch->attr.encAttr.picHeight, ch->recv_pic?"START":"STOP",
                                (ch->attr.encAttr.enType==PT_H264)?"H264":((ch->attr.encAttr.enType==PT_H265)?"H265":"JPEG"),
								ch->inStat.need_encode_frames, ch->inStat.drop_frames,
								(system_gettime(RAW) - ch->inStat.start_encode_timestamp) / 1000, ch->encodingFrameCnt, ch->endencodeFrameCnt, ch->endrelaseFrameCnt);
						dbuf += len;
						tlen += len;
						len = sprintf(dbuf, "-------------------------------------------------\n");
						dbuf += len;
						tlen += len;
						if (!bnorc && (ch->attr.encAttr.enType != PT_JPEG)) {
							len = sprintf(dbuf, "ch->index = %d\n", ch->index);
							dbuf += len;
							tlen += len;
							IMPDbgFmtEncoderRcAttr((int8_t**)&dbuf, &tmplen, ch);
							tmplen = 2000 - tmplen;
							tlen += tmplen;
						} else if ((!bnorc) && (PT_JPEG == ch->attr.encAttr.enType)){
							len = sprintf(dbuf, "ch->index = %d\n", ch->index);
							dbuf += len;
							tlen += len;
							IMPDbgFmtEncoderHelixAttr((int8_t**)&dbuf, &tmplen, ch);
							tmplen = 2000 - tmplen;
							tlen += tmplen;
						}
					}
			}
		}
	}
	tlen++;
	df->flg |= FUNC_FLAG_END;
	df->out.ret = 0;
	df->out.type = FUNC_OUT_DATA_TYPE_STR;
	df->out.size = tlen;
	return 0;
}

typedef struct dbg_enc_rc_s_data {
	int chNum;
	int offset;
	int dataSize;
	int data;
} dbg_enc_rc_s_data_t;

int dbg_enc_rc_s(void *buf, int msize, void **arg)
{
	int ret = -1;
	dformat *df = buf;
	int tlen = 0;
	char *dbuf = NULL;
	IMPEncoderRcAttr rcattr;
	int chNum = 0;
	int offset = 0;
	int dataSize = 0;
	int data = 0;
	dbg_enc_rc_s_data_t *pparam;
	void *pdata = NULL;

	if (NULL == gEncoder) {
		df->out.ret = -1;
		return -1;
	}
	dbuf = (char *)df->in.udf;
	pparam = (dbg_enc_rc_s_data_t *)dbuf;
	chNum = pparam->chNum;
	offset = pparam->offset;
	dataSize = pparam->dataSize;
	data = pparam->data;
	printf("### chNum = %d\n", chNum);
	printf("### offset = %d\n", offset);
	printf("### dataSize = %d\n", dataSize);
	printf("### data = %d\n", data);
    if ((offset >= 0) && (offset < offsetof(IMPEncoderRcAttr, attrFrmUsed))) {
        ret = IMP_Encoder_GetChnAttrRcMode(chNum, &rcattr.attrRcMode);
        if (0 != ret) {
            df->out.ret = -1;
            return -1;
        }
        pdata = &rcattr;
        pdata += offset;
        if (1 == dataSize) {
            *(uint8_t *)pdata = data;
        } else if (2 == dataSize) {
            *(uint16_t *)pdata = data;
        } else if (4 == dataSize) {
            *(uint32_t *)pdata = data;
        } else {
            df->out.ret = -1;
            return -1;
        }
        ret = IMP_Encoder_SetChnAttrRcMode(chNum, &rcattr.attrRcMode);
        if (0 != ret) {
            df->out.ret = -1;
            return -1;
        }
    } else if (offset < offsetof(IMPEncoderRcAttr, attrDenoise)) {
        IMPEncoderAttrFrmUsed frmUsed;
        ret = IMP_Encoder_GetChnFrmUsedMode(chNum, &frmUsed);
        if (ret < 0) {
            df->out.ret = -1;
            return -1;
        }

        pdata = &frmUsed;
        pdata += offset - offsetof(IMPEncoderRcAttr, attrFrmUsed);
        if (1 == dataSize) {
            *(uint8_t *)pdata = data;
        } else if (2 == dataSize) {
            *(uint16_t *)pdata = data;
        } else if (4 == dataSize) {
            *(uint32_t *)pdata = data;
        } else {
            df->out.ret = -1;
            return -1;
        }

        ret = IMP_Encoder_SetChnFrmUsedMode(chNum, &frmUsed);
        if (ret < 0) {
            df->out.ret = -1;
            return -1;
        }
    } else if (offset < offsetof(IMPEncoderRcAttr, attrHSkip)) {
        IMPEncoderAttrDenoise denoise;
        ret = IMP_Encoder_GetChnDenoise(chNum, &denoise);
        if (ret < 0) {
            df->out.ret = -1;
            return -1;
        }

        pdata = &denoise;
        pdata += offset - offsetof(IMPEncoderRcAttr, attrDenoise);
        if (1 == dataSize) {
            *(uint8_t *)pdata = data;
        } else if (2 == dataSize) {
            *(uint16_t *)pdata = data;
        } else if (4 == dataSize) {
            *(uint32_t *)pdata = data;
        } else {
            df->out.ret = -1;
            return -1;
        }
        ret = IMP_Encoder_SetChnDenoise(chNum, &denoise);
        if (ret < 0) {
            df->out.ret = -1;
            return -1;
        }
    } else if (offset < sizeof(IMPEncoderRcAttr)) {
        IMPEncoderAttrHSkip	hskip;
        ret = IMP_Encoder_GetChnHSkip(chNum, &hskip);
        if (ret < 0) {
            df->out.ret = -1;
            return -1;
        }

        pdata = &hskip;
        pdata += offset - offsetof(IMPEncoderRcAttr, attrHSkip);
        if (1 == dataSize) {
            *(uint8_t *)pdata = data;
        } else if (2 == dataSize) {
            *(uint16_t *)pdata = data;
        } else if (4 == dataSize) {
            *(uint32_t *)pdata = data;
        } else {
            df->out.ret = -1;
            return -1;
        }
        ret = IMP_Encoder_SetChnHSkip(chNum, &hskip);
        if (ret < 0) {
            df->out.ret = -1;
            return -1;
        }
    } else {
        df->out.ret = -1;
        return -1;
    }
	df->flg |= FUNC_FLAG_END;
	df->out.ret = 0;
	df->out.type = FUNC_OUT_DATA_TYPE_STR;
	df->out.size = tlen;
	return 0;
}

typedef struct dbg_enc_rcfile_s_data {
	char path[50];
}dbg_enc_rcfile_s_date_t;

int dbg_enc_rcfile_s(void *buf, int msize, void **arg)
{
	FILE *fp = NULL;
	char *str = NULL;
	char linebuf[128];
	char tmpbuf1[64];
	char tmpbuf2[64];
	RC_CFG_S_T21 rcfile;
	int encChn = 0;

	memset(linebuf, 0, 128);
	memset(tmpbuf1, 0, 64);
	memset(tmpbuf2, 0, 64);
	dformat *df = buf;
	dbg_enc_rcfile_s_date_t *pudf = (dbg_enc_rcfile_s_date_t *)df->in.udf;
	if (50 < strlen((char *)pudf->path)) {
		printf("err: file name too long\n");
		return -1;
	}

	fp = fopen(pudf->path, "r");
	if (NULL == fp) {
		printf("err:fopen err\r\n");
		return -1;
	}
	if (NULL != (str = fgets (linebuf, 128, fp))) {
		if (strlen(str) > 128) {
			printf("err: encChn bit is too long\r\n");
			fclose(fp);
			return -1;
		} else if (2 != sscanf(linebuf, "%[^:]:%s", tmpbuf1, tmpbuf2)) {
			printf("err: encChn skip config %s\r\n",linebuf);
			fclose(fp);
			return -1;
		}
	}
	char *ch = strchr(tmpbuf1, ' ');
	if (ch) *ch = 0;
	if (0 == strcmp(tmpbuf1, "encChn")) {
		encChn = strtol(tmpbuf2, NULL, 0);
	} else {
		printf("err: read encChn failed\r\n");
		fclose(fp);
		return -1;
	}
	if (encChn >= NR_MAX_ENC_CHN) {
		printf("err: encChn=%d from rcfile is over\r\n",encChn);
		fclose(fp);
		return -1;
	}
	EncChannel *enc_chn = &g_EncChannel[encChn];
	if (enc_chn) {
		if (0 != i264e_get_param(enc_chn->i264e.i264eHandler, I264E_RCFG_RCFILE_ID, &rcfile)) {
			IMP_LOG_ERR(TAG, "i264e get rcfile param failed, encchn:%d\n", encChn);
			fclose(fp);
			return -1;
		}
		if(0 != i264e_analyze_rcfile_param(fp, linebuf, tmpbuf1, tmpbuf2, &rcfile)) {
			IMP_LOG_ERR(TAG, "i264e analyze rcfile param failed, encchn:%d\n", encChn);
			fclose(fp);
			return -1;
		}
		if(0 != i264e_set_param(enc_chn->i264e.i264eHandler, I264E_RCFG_RCFILE_ID, &rcfile)) {
			IMP_LOG_ERR(TAG, "i264e set rcfile param failed, encchn:%d\n", encChn);
			fclose(fp);
			return -1;
		}
	} else {
		printf("enc_chn is NULL\r\n");
		fclose(fp);
		return -1;
	}
	fclose(fp);
	return 0;
}

int dbg_enc_superfrm_get(void *buf, int msize, void **arg)
{
    int i,j;
    dformat *df = buf;
	int len = 0;
	int tlen = 0;
	char *dbuf = NULL;

	if (NULL == gEncoder) {
		df->out.ret = -1;
		return -1;
	}
	dbuf = (char *)df->out.udf;
	Device *dev = gEncoder->device;
	int gnr = dev->nr_groups;
	for (i = 0; i < gnr; i++) {
		Group *pg = dev->groups[i];
		if (NULL != pg) {
			EncGroup *pencg = &gEncoder->encGroup[i];
			len = sprintf(dbuf, "GROUP %d\n", i);
			dbuf += len;
			tlen += len;
			for (j = 0; j < NR_MAX_ENC_CHN_IN_GROUP; j++) {
				EncChannel *ch = pencg->channel[j];
				if (NULL != ch)
					if (-1 != ch->index) {
						int tmplen = 1000;
						len = sprintf(dbuf, "\tCHANNEL %d   %5dx%5d  %8s %s \n",
								ch->index, ch->attr.encAttr.picWidth, ch->attr.encAttr.picHeight, ch->recv_pic?"START":"STOP", (ch->attr.encAttr.enType==PT_H264)?"H264":((ch->attr.encAttr.enType==PT_H265)?"H265":"JPEG"));
						dbuf += len;
						tlen += len;
						len = sprintf(dbuf, "-------------------------------------------------\n");
						dbuf += len;
						tlen += len;
						if (ch->attr.encAttr.enType != PT_JPEG) {
							len = sprintf(dbuf, "ch->index = %d\n", ch->index);
							dbuf += len;
							tlen += len;
					    	IMPDbgFmtEncoderSuperFrmInfoGet((int8_t**)&dbuf, &tmplen, ch);
							tmplen = 1000 - tmplen;
							tlen += tmplen;
						}
					}
			}
		}
	}
	tlen++;
	df->flg |= FUNC_FLAG_END;
	df->out.ret = 0;
	df->out.type = FUNC_OUT_DATA_TYPE_STR;
	df->out.size = tlen;
	return 0;
}
int dbg_enc_superfrm_set(void *buf, int msize, void **arg)
{
	int ret = -1;
	dformat *df = buf;
	int tlen = 0;
	char *dbuf = NULL;
    IMPEncoderSuperFrmCfg superfrmparam;
	int chNum = 0;
	int offset = 0;
	int dataSize = 0;
	int data = 0;
	dbg_enc_rc_s_data_t *pparam;
	void *pdata = NULL;

	if (NULL == gEncoder) {
		df->out.ret = -1;
		return -1;
	}
	dbuf = (char *)df->in.udf;
	pparam = (dbg_enc_rc_s_data_t *)dbuf;
	chNum = pparam->chNum;
	offset = pparam->offset;
	dataSize = pparam->dataSize;
	data = pparam->data;
	printf("### chNum = %d\n", chNum);
	printf("### offset = %d\n", offset);
	printf("### dataSize = %d\n", dataSize);
	printf("### data = %d\n", data);
    if ((offset >= 0) && (offset < offsetof(IMPEncoderSuperFrmCfg, rcPriority))) {
        ret = IMP_Encoder_GetSuperFrameCfg(chNum, &superfrmparam);
        if (0 != ret) {
            df->out.ret = -1;
            return -1;
        }
        pdata = &superfrmparam;
        pdata += offset;
        if (1 == dataSize) {
            *(uint8_t *)pdata = data;
        } else if (2 == dataSize) {
            *(uint16_t *)pdata = data;
        } else if (4 == dataSize) {
            *(uint32_t *)pdata = data;
        } else {
            df->out.ret = -1;
            return -1;
        }
        ret = IMP_Encoder_SetSuperFrameCfg(chNum, &superfrmparam);
        if (0 != ret) {
            df->out.ret = -1;
            return -1;
        }
    } else {
        df->out.ret = -1;
        return -1;
    }
	df->flg |= FUNC_FLAG_END;
	df->out.ret = 0;
	df->out.type = FUNC_OUT_DATA_TYPE_STR;
	df->out.size = tlen;
	return 0;
}

static unsigned long long memparse(const char *ptr, char **retptr)
{
	char *endptr;	/* local pointer to end of parsed string */

	unsigned long long ret = strtoull(ptr, &endptr, 0);

	switch (*endptr) {
	case 'G':
	case 'g':
		ret <<= 10;
	case 'M':
	case 'm':
		ret <<= 10;
	case 'K':
	case 'k':
		ret <<= 10;
		endptr++;
	default:
		break;
	}

	if (retptr)
		*retptr = endptr;

	return ret;
}

#define MEM_NAME				"ispmem"
#define MEM_DEV					"/dev/rmem"
#define SYS_CMDLINE_PATH		"/proc/cmdline"
#define NR_NCU_MEM_BANK			2

typedef struct ncu_bank {
	int index;
	int is_used;
	uint32_t paddr;
	uint32_t vaddr;
	uint32_t size;
} ncu_bank_t;

typedef struct global_ncu_info {
	uint32_t base_paddr;
	uint32_t base_vaddr;
	uint32_t total_size;
	ncu_bank_t mbank[NR_NCU_MEM_BANK]; /* 3 banks for now */
} global_ncu_info_t;

static global_ncu_info_t g_ncu_info = { 0 };

static int init_ispmem_info(void)
{
	uint32_t paddr = 0, vaddr = 0, size = 0;
	int ret;
	char buf[512] = "";
	char *p = NULL;

	FILE *fb = fopen(SYS_CMDLINE_PATH, "r");
	if(fb == NULL) {
		IMP_LOG_ERR(TAG, "%s open file (%s) error\n", __func__, SYS_CMDLINE_PATH);
		return -1;
	}

	ret = fread(buf, 1, sizeof(buf), fb);
	if(ret <= 0) {
		IMP_LOG_ERR(TAG, "%s fread (%s) error\n", __func__, SYS_CMDLINE_PATH);
		return -1;
	}

	fclose(fb);

	p = strstr(buf, MEM_NAME);
	if(p == NULL) {
		IMP_LOG_ERR(TAG, "%s fread (%s) error\n", __func__, SYS_CMDLINE_PATH);
		return -1;
	}

	char *retptr;
	size = memparse(p + 7, &retptr);

	if (*retptr == '@')
		paddr = memparse(retptr + 1, NULL);

	IMP_LOG_DBG(TAG, "ispmem Size:%d, Addr:0x%08x\n", size, paddr);

	if (paddr <= 0 || size <= 0) {
		IMP_LOG_ERR(TAG, "%s mmap Addr %x and Size %d error\n",
					__func__, paddr, size);
		return -1;
	}

	int mem_fd = -1;
	mem_fd	= open("/dev/rmem", O_RDWR);
	if (mem_fd <= 0) {
		IMP_LOG_ERR(TAG, "open %s failed\n", MEM_DEV);
		return -1;
	}

	vaddr = (uint32_t)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, paddr);
	if (vaddr <= 0) {
		IMP_LOG_ERR(TAG, "ispmem mmap failed\n");
		return -1;
	}

	memset(&g_ncu_info, 0, sizeof(global_ncu_info_t));

	g_ncu_info.base_paddr = paddr;
	g_ncu_info.base_vaddr = vaddr;
	g_ncu_info.total_size = size;

	/* The 1st bank is 5/8. */
	g_ncu_info.mbank[0].index = 0;
	g_ncu_info.mbank[0].is_used = 0;
	g_ncu_info.mbank[0].paddr = paddr;
	g_ncu_info.mbank[0].vaddr = vaddr;
	g_ncu_info.mbank[0].size = size - 800 * 608 * 5 / 2;

	g_ncu_info.mbank[1].index = 1;
	g_ncu_info.mbank[1].is_used = 0;
	g_ncu_info.mbank[1].paddr = g_ncu_info.mbank[0].paddr + g_ncu_info.mbank[0].size;
	g_ncu_info.mbank[1].vaddr = g_ncu_info.mbank[0].vaddr + g_ncu_info.mbank[0].size;
	g_ncu_info.mbank[1].size = size - g_ncu_info.mbank[0].size;

	int i;
	for (i = 0; i < NR_NCU_MEM_BANK; i++) {
		IMP_LOG_INFO(TAG, "bank-%d paddr=%08x vaddr=%08x size=%d\n", i,
					 g_ncu_info.mbank[i].paddr,
					 g_ncu_info.mbank[i].vaddr,
					 g_ncu_info.mbank[i].size);
	}

	return 0;
}

static int channel_ncu_data_init(EncChannel *enc_chn)
{
	int size_1_f = ((enc_chn->attr.encAttr.picWidth + 0xf) & ~0xf) * ((enc_chn->attr.encAttr.picHeight + 0xf) & ~0xf);
	int required_size = NCU_NEED_HOW_MUCH_MEM(size_1_f); /* backframe(w*h) outframe(w*h) + infosize(w*h/2) */
	ncu_bank_t *bank;

	if (required_size > g_ncu_info.mbank[0].size) {
		IMP_LOG_ERR(TAG, "channel-%d: picture size is too large\n",
					enc_chn->index);
		return -1;

	} else if (required_size > MAIN_STREAM_THRESTHOLD) {
		bank = &g_ncu_info.mbank[0];
		if (bank->is_used) {
			IMP_LOG_ERR(TAG, "channel-%d: no valid bank available(%d) %d\n",
						enc_chn->index, bank->index, required_size);
			return -1;
		}

	} else {
		bank = &g_ncu_info.mbank[1];
		if (bank->is_used) {
			IMP_LOG_ERR(TAG, "channel-%d: no valid bank available(%d) %d\n",
						enc_chn->index, bank->index, required_size);
			return -1;
		}
	}

	memset(&enc_chn->ncu_data, 0, sizeof(struct ncu_data));

	enc_chn->ncu_data.pri_buf = malloc(NCU_PRIV_BUF_SIZE);
	if (enc_chn->ncu_data.pri_buf == NULL) {
		IMP_LOG_ERR(TAG, "channel-%d: malloc \n",
					enc_chn->index);
		return -1;
	}
	memset(enc_chn->ncu_data.pri_buf, 0, NCU_PRIV_BUF_SIZE);

	/* Now we got a available bank. */
	enc_chn->ncu_data.data_vaddr = bank->vaddr;
	enc_chn->ncu_data.data_paddr = bank->paddr;
	enc_chn->ncu_data.frame_size = size_1_f;
	enc_chn->ncu_data.data_size = enc_chn->ncu_data.frame_size / 2;
	enc_chn->ncu_data.backup_frame_vaddr = enc_chn->ncu_data.data_vaddr + enc_chn->ncu_data.data_size;
	enc_chn->ncu_data.backup_frame_paddr = enc_chn->ncu_data.data_paddr + enc_chn->ncu_data.data_size;
	enc_chn->ncu_data.out_frame_vaddr = enc_chn->ncu_data.backup_frame_vaddr + enc_chn->ncu_data.frame_size;
	enc_chn->ncu_data.out_frame_paddr = enc_chn->ncu_data.backup_frame_paddr + enc_chn->ncu_data.frame_size;
	enc_chn->ncu_data.bank_index = bank->index;
	enc_chn->ncu_data.is_not_first_frame = false;

	memset((void *)bank->vaddr, 0, bank->size);

	if (g_ncu_enabled)
		enc_chn->ncu_data.enabled = 1;
	else
		enc_chn->ncu_data.enabled = 0;

	/* Mark this bank. */
	bank->is_used = 1;

	enc_chn->ncu_data.is_valid = true;

	IMP_LOG_INFO(TAG, "chn-%d NCU Info vaddr=%08x paddr=%08x size=%d backv=%08x backp=%08x outv=%08x outp=%08x total_size=%d\n",
				 enc_chn->index,
				 enc_chn->ncu_data.data_vaddr,
				 enc_chn->ncu_data.data_paddr,
				 enc_chn->ncu_data.data_size,
				 enc_chn->ncu_data.backup_frame_vaddr,
				 enc_chn->ncu_data.backup_frame_paddr,
				 enc_chn->ncu_data.out_frame_vaddr,
				 enc_chn->ncu_data.out_frame_paddr,
				 enc_chn->ncu_data.data_size + enc_chn->ncu_data.frame_size * 2);

	return 0;
}

static int channel_ncu_data_exit(EncChannel *enc_chn)
{
	enc_chn->ncu_data.is_valid = false;
	if (enc_chn->ncu_data.pri_buf)
		free(enc_chn->ncu_data.pri_buf);
	g_ncu_info.mbank[enc_chn->ncu_data.bank_index].is_used = 0;

	return 0;
}

static int enable_channel_ncu(EncChannel *enc_chn)
{
	if (enc_chn->ncu_data.is_valid) {
		ncu_bank_t *bank = &g_ncu_info.mbank[enc_chn->ncu_data.bank_index];
		enc_chn->ncu_data.is_not_first_frame = false;
		memset((void *)bank->vaddr, 0, bank->size);
		memset(enc_chn->ncu_data.pri_buf, 0, NCU_PRIV_BUF_SIZE);

		enc_chn->ncu_data.enabled = 1;

		return 0;
	}

	return -1;
}

static int disable_channel_ncu(EncChannel *enc_chn)
{
	if (enc_chn->ncu_data.is_valid) {
		enc_chn->ncu_data.enabled = 0;
		return 0;
	}
	return -1;
}

int IMP_Encoder_EnableAllNCUDenoise(void)
{
	int i, ret;
	uint32_t reg_temper;

	if (!IS_SOC_SERIES(T20)) {
		IMP_LOG_VERBOSE(TAG, "%s:only T20 soc supported\n", __func__);
		return -1;
	}

	return -1;
}

int IMP_Encoder_DisableAllNCUDenoise(void)
{
	int i;
	uint32_t reg_temper;

	if (!IS_SOC_SERIES(T20)) {
		IMP_LOG_VERBOSE(TAG, "%s:only T20 soc supported\n", __func__);
		return -1;
	}

	return 0;
}
